1use aes::Aes256;
8use blake2b_simd::Params as Blake2bParams;
9use fpe::ff1::{BinaryNumeralString, FF1};
10use subtle::CtOption;
11use zcash_spec::PrfExpand;
12use zip32::{ChainCode, ChildIndex, DiversifierIndex, Scope};
13
14use core::ops::AddAssign;
15use corez::io::{self, Read, Write};
16#[cfg(feature = "zeroize")]
17use zeroize::{Zeroize, ZeroizeOnDrop};
18
19use crate::zeroize_secret;
20
21use super::{Diversifier, NullifierDerivingKey, PaymentAddress, ViewingKey};
22use crate::note_encryption::PreparedIncomingViewingKey;
23use crate::{
24 constants::PROOF_GENERATION_KEY_GENERATOR,
25 keys::{
26 DecodingError, ExpandedSpendingKey, FullViewingKey, OutgoingViewingKey, SpendAuthorizingKey,
27 },
28 SaplingIvk,
29};
30
31pub const ZIP32_SAPLING_MASTER_PERSONALIZATION: &[u8; 16] = b"ZcashIP32Sapling";
32pub const ZIP32_SAPLING_FVFP_PERSONALIZATION: &[u8; 16] = b"ZcashSaplingFVFP";
33pub const ZIP32_SAPLING_INT_PERSONALIZATION: &[u8; 16] = b"Zcash_SaplingInt";
34
35pub fn sapling_address(
39 fvk: &FullViewingKey,
40 dk: &DiversifierKey,
41 j: DiversifierIndex,
42) -> Option<PaymentAddress> {
43 dk.diversifier(j)
44 .and_then(|d_j| fvk.vk.to_payment_address(d_j))
45}
46
47pub fn sapling_find_address(
52 fvk: &FullViewingKey,
53 dk: &DiversifierKey,
54 j: DiversifierIndex,
55) -> Option<(DiversifierIndex, PaymentAddress)> {
56 let (j, d_j) = dk.find_diversifier(j)?;
57 fvk.vk.to_payment_address(d_j).map(|addr| (j, addr))
58}
59
60pub fn sapling_default_address(
63 fvk: &FullViewingKey,
64 dk: &DiversifierKey,
65) -> (DiversifierIndex, PaymentAddress) {
66 sapling_find_address(fvk, dk, DiversifierIndex::new()).unwrap()
69}
70
71fn derive_child_ovk(parent: &OutgoingViewingKey, i_l: &[u8]) -> OutgoingViewingKey {
73 let mut ovk = [0u8; 32];
74 ovk.copy_from_slice(&PrfExpand::SAPLING_ZIP32_CHILD_OVK.with(i_l, &parent.0)[..32]);
75 OutgoingViewingKey(ovk)
76}
77
78pub fn sapling_derive_internal_fvk(
87 fvk: &FullViewingKey,
88 dk: &DiversifierKey,
89) -> Option<(FullViewingKey, DiversifierKey)> {
90 let i = {
91 let mut h = Blake2bParams::new()
92 .hash_length(32)
93 .personal(ZIP32_SAPLING_INT_PERSONALIZATION)
94 .to_state();
95 h.update(&fvk.to_bytes());
96 h.update(&dk.0);
97 h.finalize()
98 };
99 let i_nsk =
100 jubjub::Fr::from_bytes_wide(&PrfExpand::SAPLING_ZIP32_INTERNAL_NSK.with(i.as_bytes()));
101 let r = PrfExpand::SAPLING_ZIP32_INTERNAL_DK_OVK.with(i.as_bytes());
102 let nk_internal = NullifierDerivingKey(PROOF_GENERATION_KEY_GENERATOR * i_nsk + fvk.vk.nk().0);
104 let dk_internal = DiversifierKey(r[..32].try_into().unwrap());
105 let ovk_internal = OutgoingViewingKey(r[32..].try_into().unwrap());
106
107 ViewingKey::from_parts(fvk.vk.ak().clone(), nk_internal).map(|vk| {
108 (
109 FullViewingKey {
110 vk,
111 ovk: ovk_internal,
112 },
113 dk_internal,
114 )
115 })
116}
117
118struct FvkFingerprint([u8; 32]);
120
121impl From<&FullViewingKey> for FvkFingerprint {
122 fn from(fvk: &FullViewingKey) -> Self {
123 let mut h = Blake2bParams::new()
124 .hash_length(32)
125 .personal(ZIP32_SAPLING_FVFP_PERSONALIZATION)
126 .to_state();
127 h.update(&fvk.to_bytes());
128 let mut fvfp = [0u8; 32];
129 fvfp.copy_from_slice(h.finalize().as_bytes());
130 FvkFingerprint(fvfp)
131 }
132}
133
134impl FvkFingerprint {
135 fn tag(&self) -> FvkTag {
136 let mut tag = [0u8; 4];
137 tag.copy_from_slice(&self.0[..4]);
138 FvkTag(tag)
139 }
140}
141
142#[derive(Clone, Copy, Debug, PartialEq)]
144struct FvkTag([u8; 4]);
145
146impl FvkTag {
147 fn master() -> Self {
148 FvkTag([0u8; 4])
149 }
150
151 fn as_bytes(&self) -> &[u8; 4] {
152 &self.0
153 }
154}
155
156#[derive(Clone, Copy, Debug, PartialEq, Eq)]
158pub struct DiversifierKey([u8; 32]);
159
160#[cfg(feature = "zeroize")]
163impl Zeroize for DiversifierKey {
164 fn zeroize(&mut self) {
165 self.0.zeroize();
166 }
167}
168
169impl DiversifierKey {
170 pub fn master(sk_m: &[u8]) -> Self {
171 let mut dk_m = [0u8; 32];
172 dk_m.copy_from_slice(&PrfExpand::SAPLING_ZIP32_MASTER_DK.with(sk_m)[..32]);
173 DiversifierKey(dk_m)
174 }
175
176 pub fn from_bytes(key: [u8; 32]) -> Self {
178 DiversifierKey(key)
179 }
180
181 pub fn as_bytes(&self) -> &[u8; 32] {
183 &self.0
184 }
185
186 fn derive_child(&self, i_l: &[u8]) -> Self {
187 let mut dk = [0u8; 32];
188 dk.copy_from_slice(&PrfExpand::SAPLING_ZIP32_CHILD_DK.with(i_l, &self.0)[..32]);
189 DiversifierKey(dk)
190 }
191
192 fn try_diversifier_internal(ff: &FF1<Aes256>, j: DiversifierIndex) -> Option<Diversifier> {
193 let enc = ff
195 .encrypt(&[], &BinaryNumeralString::from_bytes_le(j.as_bytes()))
196 .unwrap();
197 let mut d_j = [0; 11];
198 d_j.copy_from_slice(&enc.to_bytes_le());
199 let diversifier = Diversifier(d_j);
200
201 diversifier.g_d().map(|_| diversifier)
203 }
204
205 pub fn diversifier(&self, j: DiversifierIndex) -> Option<Diversifier> {
208 let ff = FF1::<Aes256>::new(&self.0, 2).unwrap();
209 Self::try_diversifier_internal(&ff, j)
210 }
211
212 pub fn diversifier_index(&self, d: &Diversifier) -> DiversifierIndex {
218 let ff = FF1::<Aes256>::new(&self.0, 2).unwrap();
219 let dec = ff
220 .decrypt(&[], &BinaryNumeralString::from_bytes_le(&d.0[..]))
221 .unwrap();
222 DiversifierIndex::from(<[u8; 11]>::try_from(&dec.to_bytes_le()[..]).unwrap())
223 }
224
225 pub fn find_diversifier(
230 &self,
231 mut j: DiversifierIndex,
232 ) -> Option<(DiversifierIndex, Diversifier)> {
233 let ff = FF1::<Aes256>::new(&self.0, 2).unwrap();
234 loop {
235 match Self::try_diversifier_internal(&ff, j) {
236 Some(d_j) => return Some((j, d_j)),
237 None => {
238 if j.increment().is_err() {
239 return None;
240 }
241 }
242 }
243 }
244 }
245}
246
247#[derive(Clone, Copy, Debug, PartialEq, Eq)]
253enum KeyIndex {
254 Master,
255 Child(ChildIndex),
256}
257
258impl KeyIndex {
259 fn new(depth: u8, i: u32) -> Option<Self> {
260 match (depth == 0, i) {
261 (true, 0) => Some(KeyIndex::Master),
262 (false, _) => ChildIndex::from_index(i).map(KeyIndex::Child),
263 _ => None,
264 }
265 }
266
267 fn index(&self) -> u32 {
268 match self {
269 KeyIndex::Master => 0,
270 KeyIndex::Child(i) => i.index(),
271 }
272 }
273}
274
275#[derive(Clone)]
282pub struct ExtendedSpendingKey {
283 depth: u8,
284 parent_fvk_tag: FvkTag,
285 child_index: KeyIndex,
286 chain_code: ChainCode,
287 expsk: ExpandedSpendingKey,
288 dk: DiversifierKey,
289}
290
291#[cfg(feature = "zeroize")]
292impl Zeroize for ExtendedSpendingKey {
293 fn zeroize(&mut self) {
294 self.chain_code.zeroize();
295 self.expsk.zeroize();
296 self.dk.zeroize();
297 }
298}
299
300#[cfg(feature = "zeroize")]
301impl ZeroizeOnDrop for ExtendedSpendingKey {}
302
303#[cfg(feature = "zeroize")]
304impl Drop for ExtendedSpendingKey {
305 fn drop(&mut self) {
306 self.zeroize();
307 }
308}
309
310impl core::cmp::PartialEq for ExtendedSpendingKey {
311 fn eq(&self, rhs: &ExtendedSpendingKey) -> bool {
312 self.depth == rhs.depth
313 && self.parent_fvk_tag == rhs.parent_fvk_tag
314 && self.child_index == rhs.child_index
315 && self.chain_code == rhs.chain_code
316 && self.expsk.ask() == rhs.expsk.ask()
317 && self.expsk.nsk() == rhs.expsk.nsk()
318 && self.expsk.ovk() == rhs.expsk.ovk()
319 && self.dk == rhs.dk
320 }
321}
322
323impl core::fmt::Debug for ExtendedSpendingKey {
324 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
325 write!(
326 f,
327 "ExtendedSpendingKey(d = {}, tag_p = {:?}, i = {:?})",
328 self.depth, self.parent_fvk_tag, self.child_index
329 )
330 }
331}
332
333impl ExtendedSpendingKey {
334 fn from_parts(
339 depth: u8,
340 parent_fvk_tag: FvkTag,
341 child_index: KeyIndex,
342 chain_code: ChainCode,
343 expsk: ExpandedSpendingKey,
344 dk: DiversifierKey,
345 ) -> Option<Self> {
346 let xsk = ExtendedSpendingKey {
347 depth,
348 parent_fvk_tag,
349 child_index,
350 chain_code,
351 expsk,
352 dk,
353 };
354 sapling_derive_internal_fvk(&xsk.fvk(), &xsk.dk).map(|_| xsk)
355 }
356
357 pub fn master(seed: &[u8]) -> Option<Self> {
363 let mut i: [u8; 64] = *Blake2bParams::new()
365 .hash_length(64)
366 .personal(ZIP32_SAPLING_MASTER_PERSONALIZATION)
367 .hash(seed)
368 .as_array();
369
370 let sk_m = &i[..32];
371 let mut c_m = [0u8; 32];
372 c_m.copy_from_slice(&i[32..]);
373
374 let xsk = ExpandedSpendingKey::from_spending_key(sk_m).and_then(|expsk| {
375 Self::from_parts(
376 0,
377 FvkTag::master(),
378 KeyIndex::Master,
379 ChainCode::new(c_m),
380 expsk,
381 DiversifierKey::master(sk_m),
382 )
383 });
384 zeroize_secret(&mut c_m);
385 zeroize_secret(&mut i);
386 xsk
387 }
388
389 pub fn from_bytes(b: &[u8]) -> Result<Self, DecodingError> {
395 if b.len() != 169 {
396 return Err(DecodingError::LengthInvalid {
397 expected: 169,
398 actual: b.len(),
399 });
400 }
401
402 let depth = b[0];
403
404 let mut parent_fvk_tag = FvkTag([0; 4]);
405 parent_fvk_tag.0[..].copy_from_slice(&b[1..5]);
406
407 let mut ci_bytes = [0u8; 4];
408 ci_bytes[..].copy_from_slice(&b[5..9]);
409 let child_index = KeyIndex::new(depth, u32::from_le_bytes(ci_bytes))
410 .ok_or(DecodingError::UnsupportedChildIndex)?;
411
412 let mut c = [0u8; 32];
413 c[..].copy_from_slice(&b[9..41]);
414
415 let expsk = ExpandedSpendingKey::from_bytes(&b[41..137])?;
416
417 let mut dk = DiversifierKey([0u8; 32]);
418 dk.0[..].copy_from_slice(&b[137..169]);
419
420 Self::from_parts(
421 depth,
422 parent_fvk_tag,
423 child_index,
424 ChainCode::new(c),
425 expsk,
426 dk,
427 )
428 .ok_or(DecodingError::InvalidIvk)
429 }
430
431 pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
434 let mut depth = [0; 1];
435 reader.read_exact(&mut depth)?;
436 let depth = depth[0];
437 let mut tag = [0; 4];
438 reader.read_exact(&mut tag)?;
439 let mut child_index_bytes = [0; 4];
440 reader.read_exact(&mut child_index_bytes)?;
441 let child_index =
442 KeyIndex::new(depth, u32::from_le_bytes(child_index_bytes)).ok_or_else(|| {
443 corez::io::Error::new(
444 corez::io::ErrorKind::InvalidData,
445 "Unsupported child index in encoding",
446 )
447 })?;
448 let mut c = [0; 32];
449 reader.read_exact(&mut c)?;
450 let expsk = ExpandedSpendingKey::read(&mut reader)?;
451 let mut dk = [0; 32];
452 reader.read_exact(&mut dk)?;
453
454 let xsk = Self::from_parts(
455 depth,
456 FvkTag(tag),
457 child_index,
458 ChainCode::new(c),
459 expsk,
460 DiversifierKey(dk),
461 );
462 zeroize_secret(&mut c);
463 zeroize_secret(&mut dk);
464 xsk.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "ivk is zero"))
465 }
466
467 pub fn to_bytes(&self) -> [u8; 169] {
473 let mut result = [0u8; 169];
474 result[0] = self.depth;
475 result[1..5].copy_from_slice(&self.parent_fvk_tag.as_bytes()[..]);
476 result[5..9].copy_from_slice(&self.child_index.index().to_le_bytes()[..]);
477 result[9..41].copy_from_slice(&self.chain_code.as_bytes()[..]);
478 result[41..137].copy_from_slice(&self.expsk.to_bytes()[..]);
479 result[137..169].copy_from_slice(&self.dk.as_bytes()[..]);
480 result
481 }
482
483 pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
486 writer.write_all(&self.to_bytes())
487 }
488
489 pub fn from_path(master: &ExtendedSpendingKey, path: &[ChildIndex]) -> Option<Self> {
493 path.iter()
494 .try_fold(master.clone(), |xsk, &i| xsk.derive_child(i))
495 }
496
497 #[must_use]
504 pub fn derive_child(&self, i: ChildIndex) -> Option<Self> {
505 let fvk = self.fvk();
506 let mut tmp = {
507 let le_i = i.index().to_le_bytes();
508 let mut expsk_bytes = self.expsk.to_bytes();
509 let tmp = PrfExpand::SAPLING_ZIP32_CHILD_HARDENED.with(
510 self.chain_code.as_bytes(),
511 &expsk_bytes,
512 &self.dk.0,
513 &le_i,
514 );
515 zeroize_secret(&mut expsk_bytes);
516 tmp
517 };
518 let i_l = &tmp[..32];
519 let mut c_i = [0u8; 32];
520 c_i.copy_from_slice(&tmp[32..]);
521
522 let expsk = {
523 let mut ask_prf = PrfExpand::SAPLING_ZIP32_CHILD_I_ASK.with(i_l);
524 let mut ask = jubjub::Fr::from_bytes_wide(&ask_prf);
525 zeroize_secret(&mut ask_prf);
526 let mut nsk_prf = PrfExpand::SAPLING_ZIP32_CHILD_I_NSK.with(i_l);
527 let mut nsk = jubjub::Fr::from_bytes_wide(&nsk_prf);
528 zeroize_secret(&mut nsk_prf);
529 let mut parent_ask = self.expsk.ask().to_scalar();
530 ask.add_assign(&parent_ask);
531 zeroize_secret(&mut parent_ask);
532 nsk.add_assign(self.expsk.nsk());
533 let ovk = derive_child_ovk(self.expsk.ovk(), i_l);
534 let expsk = SpendAuthorizingKey::from_scalar(ask)
535 .and_then(|ask| ExpandedSpendingKey::from_parts(ask, nsk, ovk));
536 zeroize_secret(&mut ask);
537 zeroize_secret(&mut nsk);
538 expsk
539 };
540
541 let xsk = expsk.and_then(|expsk| {
542 Self::from_parts(
543 self.depth + 1,
544 FvkFingerprint::from(&fvk).tag(),
545 KeyIndex::Child(i),
546 ChainCode::new(c_i),
547 expsk,
548 self.dk.derive_child(i_l),
549 )
550 });
551 zeroize_secret(&mut c_i);
552 zeroize_secret(&mut tmp);
553 xsk
554 }
555
556 pub fn default_address(&self) -> (DiversifierIndex, PaymentAddress) {
559 self.to_diversifiable_full_viewing_key().default_address()
560 }
561
562 #[must_use]
571 pub fn derive_internal(&self) -> Option<Self> {
572 let i = {
573 let fvk = self.fvk();
574 let mut h = Blake2bParams::new()
575 .hash_length(32)
576 .personal(ZIP32_SAPLING_INT_PERSONALIZATION)
577 .to_state();
578 h.update(&fvk.to_bytes());
579 h.update(&self.dk.0);
580 h.finalize()
581 };
582 let mut i_nsk_prf = PrfExpand::SAPLING_ZIP32_INTERNAL_NSK.with(i.as_bytes());
583 let mut i_nsk = jubjub::Fr::from_bytes_wide(&i_nsk_prf);
584 zeroize_secret(&mut i_nsk_prf);
585 let mut r = PrfExpand::SAPLING_ZIP32_INTERNAL_DK_OVK.with(i.as_bytes());
586 let mut nsk_internal = i_nsk + self.expsk.nsk();
587 zeroize_secret(&mut i_nsk);
588 let dk_internal = DiversifierKey(r[..32].try_into().unwrap());
589 let ovk_internal = OutgoingViewingKey(r[32..].try_into().unwrap());
590 zeroize_secret(&mut r);
591
592 let expsk =
595 ExpandedSpendingKey::from_parts(self.expsk.ask().clone(), nsk_internal, ovk_internal)
596 .expect("ExtendedSpendingKey::from_parts rejects a zero internal ivk");
597 let xsk = Self::from_parts(
598 self.depth,
599 self.parent_fvk_tag,
600 self.child_index,
601 self.chain_code,
602 expsk,
603 dk_internal,
604 );
605 zeroize_secret(&mut nsk_internal);
606 xsk
607 }
608
609 pub fn expsk(&self) -> &ExpandedSpendingKey {
611 &self.expsk
612 }
613
614 fn fvk(&self) -> FullViewingKey {
616 FullViewingKey::from_expanded_spending_key(&self.expsk)
617 }
618
619 #[deprecated(note = "Use `to_diversifiable_full_viewing_key` instead.")]
620 pub fn to_extended_full_viewing_key(&self) -> ExtendedFullViewingKey {
621 ExtendedFullViewingKey {
622 depth: self.depth,
623 parent_fvk_tag: self.parent_fvk_tag,
624 child_index: self.child_index,
625 chain_code: self.chain_code,
626 fvk: self.fvk(),
627 dk: self.dk,
628 }
629 }
630
631 pub fn to_diversifiable_full_viewing_key(&self) -> DiversifiableFullViewingKey {
632 DiversifiableFullViewingKey {
633 fvk: self.fvk(),
634 dk: self.dk,
635 }
636 }
637}
638
639#[derive(Clone)]
644pub struct ExtendedFullViewingKey {
645 depth: u8,
646 parent_fvk_tag: FvkTag,
647 child_index: KeyIndex,
648 chain_code: ChainCode,
649 fvk: FullViewingKey,
650 pub(crate) dk: DiversifierKey,
651}
652
653impl core::cmp::PartialEq for ExtendedFullViewingKey {
654 fn eq(&self, rhs: &ExtendedFullViewingKey) -> bool {
655 self.depth == rhs.depth
656 && self.parent_fvk_tag == rhs.parent_fvk_tag
657 && self.child_index == rhs.child_index
658 && self.chain_code == rhs.chain_code
659 && self.fvk.vk.ak() == rhs.fvk.vk.ak()
660 && self.fvk.vk.nk() == rhs.fvk.vk.nk()
661 && self.fvk.ovk == rhs.fvk.ovk
662 && self.dk == rhs.dk
663 }
664}
665
666impl core::fmt::Debug for ExtendedFullViewingKey {
667 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
668 write!(
669 f,
670 "ExtendedFullViewingKey(d = {}, tag_p = {:?}, i = {:?})",
671 self.depth, self.parent_fvk_tag, self.child_index
672 )
673 }
674}
675
676impl ExtendedFullViewingKey {
677 pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
678 let mut depth = [0; 1];
679 reader.read_exact(&mut depth)?;
680 let depth = depth[0];
681 let mut tag = [0; 4];
682 reader.read_exact(&mut tag)?;
683 let mut child_index_bytes = [0; 4];
684 reader.read_exact(&mut child_index_bytes)?;
685 let child_index =
686 KeyIndex::new(depth, u32::from_le_bytes(child_index_bytes)).ok_or_else(|| {
687 corez::io::Error::new(
688 corez::io::ErrorKind::InvalidData,
689 "Unsupported child index in encoding",
690 )
691 })?;
692 let mut c = [0; 32];
693 reader.read_exact(&mut c)?;
694 let fvk = FullViewingKey::read(&mut reader)?;
695 let mut dk = [0; 32];
696 reader.read_exact(&mut dk)?;
697
698 let dk = DiversifierKey(dk);
699 sapling_derive_internal_fvk(&fvk, &dk)
700 .map(|_| ExtendedFullViewingKey {
701 depth,
702 parent_fvk_tag: FvkTag(tag),
703 child_index,
704 chain_code: ChainCode::new(c),
705 fvk,
706 dk,
707 })
708 .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "internal ivk is zero"))
709 }
710
711 pub fn fvk(&self) -> &FullViewingKey {
713 &self.fvk
714 }
715
716 pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
717 writer.write_all(&[self.depth])?;
718 writer.write_all(&self.parent_fvk_tag.0)?;
719 writer.write_all(&self.child_index.index().to_le_bytes())?;
720 writer.write_all(self.chain_code.as_bytes())?;
721 writer.write_all(&self.fvk.to_bytes())?;
722 writer.write_all(&self.dk.0)?;
723
724 Ok(())
725 }
726
727 pub fn address(&self, j: DiversifierIndex) -> Option<PaymentAddress> {
731 sapling_address(&self.fvk, &self.dk, j)
732 }
733
734 pub fn find_address(&self, j: DiversifierIndex) -> Option<(DiversifierIndex, PaymentAddress)> {
739 sapling_find_address(&self.fvk, &self.dk, j)
740 }
741
742 pub fn default_address(&self) -> (DiversifierIndex, PaymentAddress) {
745 sapling_default_address(&self.fvk, &self.dk)
746 }
747
748 #[must_use]
759 pub fn derive_internal(&self) -> Option<Self> {
760 let (fvk_internal, dk_internal) = sapling_derive_internal_fvk(&self.fvk, &self.dk)
761 .expect("ExtendedFullViewingKey constructors reject a zero internal ivk");
762
763 sapling_derive_internal_fvk(&fvk_internal, &dk_internal).map(|_| ExtendedFullViewingKey {
764 depth: self.depth,
765 parent_fvk_tag: self.parent_fvk_tag,
766 child_index: self.child_index,
767 chain_code: self.chain_code,
768 fvk: fvk_internal,
769 dk: dk_internal,
770 })
771 }
772
773 pub fn to_diversifiable_full_viewing_key(&self) -> DiversifiableFullViewingKey {
774 DiversifiableFullViewingKey {
775 fvk: self.fvk.clone(),
776 dk: self.dk,
777 }
778 }
779}
780
781#[derive(Clone, Debug, PartialEq, Eq)]
794pub struct DiversifiableFullViewingKey {
795 fvk: FullViewingKey,
796 dk: DiversifierKey,
797}
798
799impl From<ExtendedFullViewingKey> for DiversifiableFullViewingKey {
800 fn from(extfvk: ExtendedFullViewingKey) -> Self {
801 DiversifiableFullViewingKey {
802 fvk: extfvk.fvk,
803 dk: extfvk.dk,
804 }
805 }
806}
807
808impl From<&ExtendedFullViewingKey> for DiversifiableFullViewingKey {
809 fn from(extfvk: &ExtendedFullViewingKey) -> Self {
810 extfvk.to_diversifiable_full_viewing_key()
811 }
812}
813
814impl DiversifiableFullViewingKey {
815 pub fn from_bytes(bytes: &[u8; 128]) -> Option<Self> {
821 let fvk = FullViewingKey::read(&bytes[..96]).ok()?;
822 let dk = DiversifierKey::from_bytes(bytes[96..].try_into().unwrap());
823 sapling_derive_internal_fvk(&fvk, &dk).map(|_| Self { fvk, dk })
824 }
825
826 pub fn to_bytes(&self) -> [u8; 128] {
828 let mut bytes = [0; 128];
829 self.fvk
830 .write(&mut bytes[..96])
831 .expect("slice should be the correct length");
832 bytes[96..].copy_from_slice(&self.dk.as_bytes()[..]);
833 bytes
834 }
835
836 fn internal_parts(&self) -> (FullViewingKey, DiversifierKey) {
839 sapling_derive_internal_fvk(&self.fvk, &self.dk)
840 .expect("DiversifiableFullViewingKey constructors reject a zero internal ivk")
841 }
842
843 pub fn fvk(&self) -> &FullViewingKey {
845 &self.fvk
846 }
847
848 pub fn to_internal_fvk(&self) -> FullViewingKey {
850 self.internal_parts().0
851 }
852
853 pub fn to_nk(&self, scope: Scope) -> NullifierDerivingKey {
857 match scope {
858 Scope::External => *self.fvk.vk.nk(),
859 Scope::Internal => *self.internal_parts().0.vk.nk(),
860 }
861 }
862
863 pub fn to_ivk(&self, scope: Scope) -> SaplingIvk {
866 match scope {
867 Scope::External => self.fvk.vk.ivk(),
868 Scope::Internal => self.internal_parts().0.vk.ivk(),
869 }
870 }
871
872 pub fn to_external_ivk(&self) -> IncomingViewingKey {
874 IncomingViewingKey {
875 dk: self.dk,
876 ivk: self.to_ivk(Scope::External),
877 }
878 }
879
880 pub fn to_ovk(&self, scope: Scope) -> OutgoingViewingKey {
882 match scope {
883 Scope::External => self.fvk.ovk,
884 Scope::Internal => self.internal_parts().0.ovk,
885 }
886 }
887
888 pub fn address(&self, j: DiversifierIndex) -> Option<PaymentAddress> {
893 self.to_external_ivk().address_at(j)
894 }
895
896 pub fn find_address(&self, j: DiversifierIndex) -> Option<(DiversifierIndex, PaymentAddress)> {
905 self.to_external_ivk().find_address(j)
906 }
907
908 pub fn default_address(&self) -> (DiversifierIndex, PaymentAddress) {
911 self.to_external_ivk().find_address(0u32).unwrap()
912 }
913
914 pub fn diversified_address(&self, diversifier: Diversifier) -> Option<PaymentAddress> {
919 self.to_external_ivk().address(diversifier)
920 }
921
922 pub fn change_address(&self) -> (DiversifierIndex, PaymentAddress) {
928 let (fvk, dk) = self.internal_parts();
929 sapling_default_address(&fvk, &dk)
930 }
931
932 pub fn diversified_change_address(&self, diversifier: Diversifier) -> Option<PaymentAddress> {
937 self.internal_parts().0.vk.to_payment_address(diversifier)
938 }
939
940 pub fn decrypt_diversifier(&self, addr: &PaymentAddress) -> Option<(DiversifierIndex, Scope)> {
950 let j_external = self.dk.diversifier_index(addr.diversifier());
951 if self.address(j_external).as_ref() == Some(addr) {
952 return Some((j_external, Scope::External));
953 }
954
955 let j_internal = self
956 .internal_parts()
957 .1
958 .diversifier_index(addr.diversifier());
959 if self.address(j_internal).as_ref() == Some(addr) {
960 return Some((j_internal, Scope::Internal));
961 }
962
963 None
964 }
965}
966
967#[derive(Clone, Debug, PartialEq, Eq)]
978pub struct IncomingViewingKey {
979 dk: DiversifierKey,
980 ivk: SaplingIvk,
981}
982
983impl IncomingViewingKey {
984 pub fn from_bytes(bytes: &[u8; 64]) -> CtOption<Self> {
990 SaplingIvk::parse_with(&bytes[32..].try_into().unwrap(), |ivk| IncomingViewingKey {
991 dk: DiversifierKey::from_bytes(bytes[..32].try_into().unwrap()),
992 ivk,
993 })
994 }
995
996 pub fn to_bytes(&self) -> [u8; 64] {
998 let mut bytes = [0; 64];
999 bytes[..32].copy_from_slice(&self.dk.as_bytes()[..]);
1000 bytes[32..].copy_from_slice(&self.ivk.to_repr()[..]);
1001 bytes
1002 }
1003
1004 pub fn prepare(&self) -> PreparedIncomingViewingKey {
1006 PreparedIncomingViewingKey::new(&self.ivk)
1007 }
1008
1009 pub fn address_at(&self, j: impl Into<DiversifierIndex>) -> Option<PaymentAddress> {
1014 self.dk
1015 .diversifier(j.into())
1016 .and_then(|d_j| self.ivk.to_payment_address(d_j))
1017 }
1018
1019 pub fn address(&self, diversifier: Diversifier) -> Option<PaymentAddress> {
1024 self.ivk.to_payment_address(diversifier)
1025 }
1026
1027 pub fn find_address(
1036 &self,
1037 j: impl Into<DiversifierIndex>,
1038 ) -> Option<(DiversifierIndex, PaymentAddress)> {
1039 let (j, d_j) = self.dk.find_diversifier(j.into())?;
1040 self.ivk.to_payment_address(d_j).map(|addr| (j, addr))
1041 }
1042
1043 pub fn decrypt_diversifier(&self, addr: &PaymentAddress) -> Option<DiversifierIndex> {
1053 let j = self.dk.diversifier_index(addr.diversifier());
1054 if self.address_at(j).as_ref() == Some(addr) {
1055 Some(j)
1056 } else {
1057 None
1058 }
1059 }
1060}
1061
1062#[cfg(test)]
1063mod tests {
1064 use super::*;
1065
1066 use super::{DiversifiableFullViewingKey, ExtendedSpendingKey};
1067 use ff::PrimeField;
1068 use group::GroupEncoding;
1069
1070 #[test]
1071 #[allow(deprecated)]
1072 fn derive_hardened_child() {
1073 let seed = [0; 32];
1074 let xsk_m = ExtendedSpendingKey::master(&seed).unwrap();
1075
1076 let i_5h = ChildIndex::hardened(5);
1077 let _ = xsk_m.derive_child(i_5h).unwrap();
1078 }
1079
1080 #[test]
1081 fn path() {
1082 let seed = [0; 32];
1083 let xsk_m = ExtendedSpendingKey::master(&seed).unwrap();
1084
1085 let xsk_5h = xsk_m.derive_child(ChildIndex::hardened(5)).unwrap();
1086 assert_eq!(
1087 ExtendedSpendingKey::from_path(&xsk_m, &[ChildIndex::hardened(5)]).unwrap(),
1088 xsk_5h
1089 );
1090
1091 let xsk_5h_7 = xsk_5h.derive_child(ChildIndex::hardened(7)).unwrap();
1092 assert_eq!(
1093 ExtendedSpendingKey::from_path(
1094 &xsk_m,
1095 &[ChildIndex::hardened(5), ChildIndex::hardened(7)]
1096 )
1097 .unwrap(),
1098 xsk_5h_7
1099 );
1100 }
1101
1102 #[test]
1103 fn diversifier() {
1104 let dk = DiversifierKey([0; 32]);
1105 let j_0 = DiversifierIndex::new();
1106 let j_1 = DiversifierIndex::from([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
1107 let j_2 = DiversifierIndex::from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
1108 let j_3 = DiversifierIndex::from([3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
1109 let d_0 = [220, 231, 126, 188, 236, 10, 38, 175, 214, 153, 140];
1111 let d_3 = [60, 253, 170, 8, 171, 147, 220, 31, 3, 144, 34];
1112
1113 let d_j = dk.diversifier(j_0).unwrap();
1115 assert_eq!(d_j.0, d_0);
1116 assert_eq!(dk.diversifier_index(&Diversifier(d_0)), j_0);
1117
1118 assert_eq!(dk.diversifier(j_1), None);
1120
1121 assert_eq!(dk.diversifier(j_2), None);
1123
1124 let d_j = dk.diversifier(j_3).unwrap();
1126 assert_eq!(d_j.0, d_3);
1127 assert_eq!(dk.diversifier_index(&Diversifier(d_3)), j_3);
1128 }
1129
1130 #[test]
1131 fn diversifier_index_from() {
1132 let di32: u32 = 0xa0b0c0d0;
1133 assert_eq!(
1134 DiversifierIndex::from(di32),
1135 DiversifierIndex::from([0xd0, 0xc0, 0xb0, 0xa0, 0, 0, 0, 0, 0, 0, 0])
1136 );
1137 let di64: u64 = 0x0102030405060708;
1138 assert_eq!(
1139 DiversifierIndex::from(di64),
1140 DiversifierIndex::from([8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0])
1141 );
1142 }
1143
1144 #[test]
1145 fn find_diversifier() {
1146 let dk = DiversifierKey([0; 32]);
1147 let j_0 = DiversifierIndex::new();
1148 let j_1 = DiversifierIndex::from([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
1149 let j_2 = DiversifierIndex::from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
1150 let j_3 = DiversifierIndex::from([3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
1151 let d_0 = [220, 231, 126, 188, 236, 10, 38, 175, 214, 153, 140];
1153 let d_3 = [60, 253, 170, 8, 171, 147, 220, 31, 3, 144, 34];
1154
1155 let (j, d_j) = dk.find_diversifier(j_0).unwrap();
1157 assert_eq!(j, j_0);
1158 assert_eq!(d_j.0, d_0);
1159
1160 let (j, d_j) = dk.find_diversifier(j_1).unwrap();
1162 assert_eq!(j, j_3);
1163 assert_eq!(d_j.0, d_3);
1164
1165 let (j, d_j) = dk.find_diversifier(j_2).unwrap();
1167 assert_eq!(j, j_3);
1168 assert_eq!(d_j.0, d_3);
1169
1170 let (j, d_j) = dk.find_diversifier(j_3).unwrap();
1172 assert_eq!(j, j_3);
1173 assert_eq!(d_j.0, d_3);
1174 }
1175
1176 #[test]
1177 fn dfvk_round_trip() {
1178 let dfvk = {
1179 let extsk = ExtendedSpendingKey::master(&[]).unwrap();
1180 #[allow(deprecated)]
1181 let extfvk = extsk.to_extended_full_viewing_key();
1182 DiversifiableFullViewingKey::from(extfvk)
1183 };
1184
1185 let dfvk_bytes = dfvk.to_bytes();
1187 let dfvk_parsed = DiversifiableFullViewingKey::from_bytes(&dfvk_bytes).unwrap();
1188 assert_eq!(dfvk_parsed.fvk.vk.ak(), dfvk.fvk.vk.ak());
1189 assert_eq!(dfvk_parsed.fvk.vk.nk(), dfvk.fvk.vk.nk());
1190 assert_eq!(dfvk_parsed.fvk.ovk, dfvk.fvk.ovk);
1191 assert_eq!(dfvk_parsed.dk, dfvk.dk);
1192
1193 assert_eq!(dfvk_parsed.to_bytes(), dfvk_bytes);
1195 }
1196
1197 #[test]
1198 fn ivk_round_trip() {
1199 let ivk = {
1200 let extsk = ExtendedSpendingKey::master(&[]).unwrap();
1201 #[allow(deprecated)]
1202 let extfvk = extsk.to_extended_full_viewing_key();
1203 DiversifiableFullViewingKey::from(extfvk).to_external_ivk()
1204 };
1205
1206 let ivk_bytes = ivk.to_bytes();
1208 let ivk_parsed = IncomingViewingKey::from_bytes(&ivk_bytes).unwrap();
1209 assert_eq!(ivk_parsed.dk, ivk.dk);
1210 assert_eq!(ivk_parsed.ivk, ivk.ivk);
1211
1212 assert_eq!(ivk_parsed.to_bytes(), ivk_bytes);
1214 }
1215
1216 #[test]
1217 fn ivk_must_be_nonzero() {
1218 let ivk = {
1219 let extsk = ExtendedSpendingKey::master(&[]).unwrap();
1220 extsk.to_diversifiable_full_viewing_key().to_external_ivk()
1221 };
1222
1223 let mut ivk_bytes = ivk.to_bytes();
1224 ivk_bytes[32..].fill(0);
1225 assert!(bool::from(
1226 IncomingViewingKey::from_bytes(&ivk_bytes).is_none()
1227 ));
1228 }
1229
1230 #[test]
1231 fn address() {
1232 let seed = [0; 32];
1233 let xsk_m = ExtendedSpendingKey::master(&seed).unwrap();
1234 let xfvk_m = xsk_m.to_diversifiable_full_viewing_key();
1235 let j_0 = DiversifierIndex::new();
1236 let addr_m = xfvk_m.address(j_0).unwrap();
1237 assert_eq!(
1238 addr_m.diversifier().0,
1239 [59, 246, 250, 31, 131, 191, 69, 99, 200, 167, 19]
1241 );
1242
1243 let j_1 = DiversifierIndex::from([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
1244 assert_eq!(xfvk_m.address(j_1), None);
1245 }
1246
1247 #[test]
1248 fn default_address() {
1249 let seed = [0; 32];
1250 let xsk_m = ExtendedSpendingKey::master(&seed).unwrap();
1251 let (j_m, addr_m) = xsk_m.default_address();
1252 assert_eq!(j_m.as_bytes(), &[0; 11]);
1253 assert_eq!(
1254 addr_m.diversifier().0,
1255 [59, 246, 250, 31, 131, 191, 69, 99, 200, 167, 19]
1257 );
1258 }
1259
1260 #[test]
1261 #[allow(deprecated)]
1262 fn read_write() {
1263 let seed = [0; 32];
1264 let xsk = ExtendedSpendingKey::master(&seed).unwrap();
1265 let fvk = xsk.to_extended_full_viewing_key();
1266
1267 let mut ser = vec![];
1268 xsk.write(&mut ser).unwrap();
1269 let xsk2 = ExtendedSpendingKey::read(&ser[..]).unwrap();
1270 assert_eq!(xsk2, xsk);
1271
1272 let mut ser = vec![];
1273 fvk.write(&mut ser).unwrap();
1274 let fvk2 = ExtendedFullViewingKey::read(&ser[..]).unwrap();
1275 assert_eq!(fvk2, fvk);
1276 }
1277
1278 #[test]
1279 #[allow(deprecated)]
1280 fn test_vectors() {
1281 struct TestVector {
1282 ask: Option<[u8; 32]>,
1283 nsk: Option<[u8; 32]>,
1284 ovk: [u8; 32],
1285 dk: [u8; 32],
1286 c: [u8; 32],
1287 ak: [u8; 32],
1288 nk: [u8; 32],
1289 ivk: [u8; 32],
1290 xsk: Option<[u8; 169]>,
1291 xfvk: [u8; 169],
1292 fp: [u8; 32],
1293 d0: Option<[u8; 11]>,
1294 d1: Option<[u8; 11]>,
1295 d2: Option<[u8; 11]>,
1296 dmax: Option<[u8; 11]>,
1297 internal_nsk: Option<[u8; 32]>,
1298 internal_ovk: [u8; 32],
1299 internal_dk: [u8; 32],
1300 internal_nk: [u8; 32],
1301 internal_ivk: [u8; 32],
1302 internal_xsk: Option<[u8; 169]>,
1303 internal_xfvk: [u8; 169],
1304 internal_fp: [u8; 32],
1305 }
1306
1307 let test_vectors = [
1309 TestVector {
1310 ask: Some([
1311 0xb6, 0xc0, 0x0c, 0x93, 0xd3, 0x60, 0x32, 0xb9, 0xa2, 0x68, 0xe9, 0x9e, 0x86,
1312 0xa8, 0x60, 0x77, 0x65, 0x60, 0xbf, 0x0e, 0x83, 0xc1, 0xa1, 0x0b, 0x51, 0xf6,
1313 0x07, 0xc9, 0x54, 0x74, 0x25, 0x06,
1314 ]),
1315 nsk: Some([
1316 0x82, 0x04, 0xed, 0xe8, 0x3b, 0x2f, 0x1f, 0xbd, 0x84, 0xf9, 0xb4, 0x5d, 0x7f,
1317 0x99, 0x6e, 0x2e, 0xbd, 0x0a, 0x03, 0x0a, 0xd2, 0x43, 0xb4, 0x8e, 0xd3, 0x9f,
1318 0x74, 0x8a, 0x88, 0x21, 0xea, 0x06,
1319 ]),
1320 ovk: [
1321 0x39, 0x58, 0x84, 0x89, 0x03, 0x23, 0xb9, 0xd4, 0x93, 0x3c, 0x02, 0x1d, 0xb8,
1322 0x9b, 0xcf, 0x76, 0x7d, 0xf2, 0x19, 0x77, 0xb2, 0xff, 0x06, 0x83, 0x84, 0x83,
1323 0x21, 0xa4, 0xdf, 0x4a, 0xfb, 0x21,
1324 ],
1325 dk: [
1326 0x77, 0xc1, 0x7c, 0xb7, 0x5b, 0x77, 0x96, 0xaf, 0xb3, 0x9f, 0x0f, 0x3e, 0x91,
1327 0xc9, 0x24, 0x60, 0x7d, 0xa5, 0x6f, 0xa9, 0xa2, 0x0e, 0x28, 0x35, 0x09, 0xbc,
1328 0x8a, 0x3e, 0xf9, 0x96, 0xa1, 0x72,
1329 ],
1330 c: [
1331 0xd0, 0x94, 0x7c, 0x4b, 0x03, 0xbf, 0x72, 0xa3, 0x7a, 0xb4, 0x4f, 0x72, 0x27,
1332 0x6d, 0x1c, 0xf3, 0xfd, 0xcd, 0x7e, 0xbf, 0x3e, 0x73, 0x34, 0x8b, 0x7e, 0x55,
1333 0x0d, 0x75, 0x20, 0x18, 0x66, 0x8e,
1334 ],
1335 ak: [
1336 0x93, 0x44, 0x2e, 0x5f, 0xef, 0xfb, 0xff, 0x16, 0xe7, 0x21, 0x72, 0x02, 0xdc,
1337 0x73, 0x06, 0x72, 0x9f, 0xff, 0xfe, 0x85, 0xaf, 0x56, 0x83, 0xbc, 0xe2, 0x64,
1338 0x2e, 0x3e, 0xeb, 0x5d, 0x38, 0x71,
1339 ],
1340 nk: [
1341 0xdc, 0xe8, 0xe7, 0xed, 0xec, 0xe0, 0x4b, 0x89, 0x50, 0x41, 0x7f, 0x85, 0xba,
1342 0x57, 0x69, 0x1b, 0x78, 0x3c, 0x45, 0xb1, 0xa2, 0x74, 0x22, 0xdb, 0x16, 0x93,
1343 0xdc, 0xeb, 0x67, 0xb1, 0x01, 0x06,
1344 ],
1345 ivk: [
1346 0x48, 0x47, 0xa1, 0x30, 0xe7, 0x99, 0xd3, 0xdb, 0xea, 0x36, 0xa1, 0xc1, 0x64,
1347 0x67, 0xd6, 0x21, 0xfb, 0x2d, 0x80, 0xe3, 0x0b, 0x3b, 0x1d, 0x1a, 0x42, 0x68,
1348 0x93, 0x41, 0x5d, 0xad, 0x66, 0x01,
1349 ],
1350 xsk: Some([
1351 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x94, 0x7c, 0x4b,
1352 0x03, 0xbf, 0x72, 0xa3, 0x7a, 0xb4, 0x4f, 0x72, 0x27, 0x6d, 0x1c, 0xf3, 0xfd,
1353 0xcd, 0x7e, 0xbf, 0x3e, 0x73, 0x34, 0x8b, 0x7e, 0x55, 0x0d, 0x75, 0x20, 0x18,
1354 0x66, 0x8e, 0xb6, 0xc0, 0x0c, 0x93, 0xd3, 0x60, 0x32, 0xb9, 0xa2, 0x68, 0xe9,
1355 0x9e, 0x86, 0xa8, 0x60, 0x77, 0x65, 0x60, 0xbf, 0x0e, 0x83, 0xc1, 0xa1, 0x0b,
1356 0x51, 0xf6, 0x07, 0xc9, 0x54, 0x74, 0x25, 0x06, 0x82, 0x04, 0xed, 0xe8, 0x3b,
1357 0x2f, 0x1f, 0xbd, 0x84, 0xf9, 0xb4, 0x5d, 0x7f, 0x99, 0x6e, 0x2e, 0xbd, 0x0a,
1358 0x03, 0x0a, 0xd2, 0x43, 0xb4, 0x8e, 0xd3, 0x9f, 0x74, 0x8a, 0x88, 0x21, 0xea,
1359 0x06, 0x39, 0x58, 0x84, 0x89, 0x03, 0x23, 0xb9, 0xd4, 0x93, 0x3c, 0x02, 0x1d,
1360 0xb8, 0x9b, 0xcf, 0x76, 0x7d, 0xf2, 0x19, 0x77, 0xb2, 0xff, 0x06, 0x83, 0x84,
1361 0x83, 0x21, 0xa4, 0xdf, 0x4a, 0xfb, 0x21, 0x77, 0xc1, 0x7c, 0xb7, 0x5b, 0x77,
1362 0x96, 0xaf, 0xb3, 0x9f, 0x0f, 0x3e, 0x91, 0xc9, 0x24, 0x60, 0x7d, 0xa5, 0x6f,
1363 0xa9, 0xa2, 0x0e, 0x28, 0x35, 0x09, 0xbc, 0x8a, 0x3e, 0xf9, 0x96, 0xa1, 0x72,
1364 ]),
1365 xfvk: [
1366 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x94, 0x7c, 0x4b,
1367 0x03, 0xbf, 0x72, 0xa3, 0x7a, 0xb4, 0x4f, 0x72, 0x27, 0x6d, 0x1c, 0xf3, 0xfd,
1368 0xcd, 0x7e, 0xbf, 0x3e, 0x73, 0x34, 0x8b, 0x7e, 0x55, 0x0d, 0x75, 0x20, 0x18,
1369 0x66, 0x8e, 0x93, 0x44, 0x2e, 0x5f, 0xef, 0xfb, 0xff, 0x16, 0xe7, 0x21, 0x72,
1370 0x02, 0xdc, 0x73, 0x06, 0x72, 0x9f, 0xff, 0xfe, 0x85, 0xaf, 0x56, 0x83, 0xbc,
1371 0xe2, 0x64, 0x2e, 0x3e, 0xeb, 0x5d, 0x38, 0x71, 0xdc, 0xe8, 0xe7, 0xed, 0xec,
1372 0xe0, 0x4b, 0x89, 0x50, 0x41, 0x7f, 0x85, 0xba, 0x57, 0x69, 0x1b, 0x78, 0x3c,
1373 0x45, 0xb1, 0xa2, 0x74, 0x22, 0xdb, 0x16, 0x93, 0xdc, 0xeb, 0x67, 0xb1, 0x01,
1374 0x06, 0x39, 0x58, 0x84, 0x89, 0x03, 0x23, 0xb9, 0xd4, 0x93, 0x3c, 0x02, 0x1d,
1375 0xb8, 0x9b, 0xcf, 0x76, 0x7d, 0xf2, 0x19, 0x77, 0xb2, 0xff, 0x06, 0x83, 0x84,
1376 0x83, 0x21, 0xa4, 0xdf, 0x4a, 0xfb, 0x21, 0x77, 0xc1, 0x7c, 0xb7, 0x5b, 0x77,
1377 0x96, 0xaf, 0xb3, 0x9f, 0x0f, 0x3e, 0x91, 0xc9, 0x24, 0x60, 0x7d, 0xa5, 0x6f,
1378 0xa9, 0xa2, 0x0e, 0x28, 0x35, 0x09, 0xbc, 0x8a, 0x3e, 0xf9, 0x96, 0xa1, 0x72,
1379 ],
1380 fp: [
1381 0x14, 0xc2, 0x71, 0x3a, 0xdc, 0xe9, 0x3a, 0x83, 0x0e, 0xa8, 0x3a, 0x05, 0x19,
1382 0x08, 0xb7, 0x44, 0x77, 0x83, 0xf5, 0xd1, 0x06, 0xc0, 0x98, 0x5e, 0x02, 0x55,
1383 0x0e, 0x42, 0x6f, 0x27, 0x59, 0x7c,
1384 ],
1385 d0: Some([
1386 0xd8, 0x62, 0x1b, 0x98, 0x1c, 0xf3, 0x00, 0xe9, 0xd4, 0xcc, 0x89,
1387 ]),
1388 d1: Some([
1389 0x48, 0xea, 0x17, 0xa1, 0x99, 0xc8, 0x4b, 0xd1, 0xba, 0xa5, 0xd4,
1390 ]),
1391 d2: None,
1392 dmax: None,
1393 internal_nsk: Some([
1394 0x51, 0x12, 0x33, 0x63, 0x6b, 0x95, 0xfd, 0x0a, 0xfb, 0x6b, 0xf8, 0x19, 0x3a,
1395 0x7d, 0x8f, 0x49, 0xef, 0xd7, 0x36, 0xa9, 0x88, 0x77, 0x5c, 0x54, 0xf9, 0x56,
1396 0x68, 0x76, 0x46, 0xea, 0xab, 0x07,
1397 ]),
1398 internal_ovk: [
1399 0x9d, 0xc4, 0x77, 0xfe, 0x1e, 0x7d, 0x28, 0x29, 0x13, 0xf6, 0x51, 0x65, 0x4d,
1400 0x39, 0x85, 0xf0, 0x9d, 0x53, 0xc2, 0xd3, 0xb5, 0x76, 0x3d, 0x7a, 0x72, 0x3b,
1401 0xcb, 0xd6, 0xee, 0x05, 0x3d, 0x5a,
1402 ],
1403 internal_dk: [
1404 0x40, 0xdd, 0xc5, 0x6e, 0x69, 0x75, 0x13, 0x8c, 0x08, 0x39, 0xe5, 0x80, 0xb5,
1405 0x4d, 0x6d, 0x99, 0x9d, 0xc6, 0x16, 0x84, 0x3c, 0xfe, 0x04, 0x1e, 0x8f, 0x38,
1406 0x8b, 0x12, 0x4e, 0xf7, 0xb5, 0xed,
1407 ],
1408 internal_nk: [
1409 0xa3, 0x83, 0x1a, 0x5c, 0x69, 0x33, 0xf8, 0xec, 0x6a, 0xa5, 0xce, 0x31, 0x6c,
1410 0x50, 0x8b, 0x79, 0x91, 0xcd, 0x94, 0xd3, 0xbd, 0xb7, 0x00, 0xa1, 0xc4, 0x27,
1411 0xa6, 0xae, 0x15, 0xe7, 0x2f, 0xb5,
1412 ],
1413 internal_ivk: [
1414 0x79, 0x05, 0x77, 0x32, 0x1c, 0x51, 0x18, 0x04, 0x63, 0x6e, 0xe6, 0xba, 0xa4,
1415 0xee, 0xa7, 0x79, 0xb4, 0xa4, 0x6a, 0x5a, 0x12, 0xf8, 0x5d, 0x36, 0x50, 0x74,
1416 0xa0, 0x9d, 0x05, 0x4f, 0x34, 0x01,
1417 ],
1418 internal_xsk: Some([
1419 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x94, 0x7c, 0x4b,
1420 0x03, 0xbf, 0x72, 0xa3, 0x7a, 0xb4, 0x4f, 0x72, 0x27, 0x6d, 0x1c, 0xf3, 0xfd,
1421 0xcd, 0x7e, 0xbf, 0x3e, 0x73, 0x34, 0x8b, 0x7e, 0x55, 0x0d, 0x75, 0x20, 0x18,
1422 0x66, 0x8e, 0xb6, 0xc0, 0x0c, 0x93, 0xd3, 0x60, 0x32, 0xb9, 0xa2, 0x68, 0xe9,
1423 0x9e, 0x86, 0xa8, 0x60, 0x77, 0x65, 0x60, 0xbf, 0x0e, 0x83, 0xc1, 0xa1, 0x0b,
1424 0x51, 0xf6, 0x07, 0xc9, 0x54, 0x74, 0x25, 0x06, 0x51, 0x12, 0x33, 0x63, 0x6b,
1425 0x95, 0xfd, 0x0a, 0xfb, 0x6b, 0xf8, 0x19, 0x3a, 0x7d, 0x8f, 0x49, 0xef, 0xd7,
1426 0x36, 0xa9, 0x88, 0x77, 0x5c, 0x54, 0xf9, 0x56, 0x68, 0x76, 0x46, 0xea, 0xab,
1427 0x07, 0x9d, 0xc4, 0x77, 0xfe, 0x1e, 0x7d, 0x28, 0x29, 0x13, 0xf6, 0x51, 0x65,
1428 0x4d, 0x39, 0x85, 0xf0, 0x9d, 0x53, 0xc2, 0xd3, 0xb5, 0x76, 0x3d, 0x7a, 0x72,
1429 0x3b, 0xcb, 0xd6, 0xee, 0x05, 0x3d, 0x5a, 0x40, 0xdd, 0xc5, 0x6e, 0x69, 0x75,
1430 0x13, 0x8c, 0x08, 0x39, 0xe5, 0x80, 0xb5, 0x4d, 0x6d, 0x99, 0x9d, 0xc6, 0x16,
1431 0x84, 0x3c, 0xfe, 0x04, 0x1e, 0x8f, 0x38, 0x8b, 0x12, 0x4e, 0xf7, 0xb5, 0xed,
1432 ]),
1433 internal_xfvk: [
1434 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x94, 0x7c, 0x4b,
1435 0x03, 0xbf, 0x72, 0xa3, 0x7a, 0xb4, 0x4f, 0x72, 0x27, 0x6d, 0x1c, 0xf3, 0xfd,
1436 0xcd, 0x7e, 0xbf, 0x3e, 0x73, 0x34, 0x8b, 0x7e, 0x55, 0x0d, 0x75, 0x20, 0x18,
1437 0x66, 0x8e, 0x93, 0x44, 0x2e, 0x5f, 0xef, 0xfb, 0xff, 0x16, 0xe7, 0x21, 0x72,
1438 0x02, 0xdc, 0x73, 0x06, 0x72, 0x9f, 0xff, 0xfe, 0x85, 0xaf, 0x56, 0x83, 0xbc,
1439 0xe2, 0x64, 0x2e, 0x3e, 0xeb, 0x5d, 0x38, 0x71, 0xa3, 0x83, 0x1a, 0x5c, 0x69,
1440 0x33, 0xf8, 0xec, 0x6a, 0xa5, 0xce, 0x31, 0x6c, 0x50, 0x8b, 0x79, 0x91, 0xcd,
1441 0x94, 0xd3, 0xbd, 0xb7, 0x00, 0xa1, 0xc4, 0x27, 0xa6, 0xae, 0x15, 0xe7, 0x2f,
1442 0xb5, 0x9d, 0xc4, 0x77, 0xfe, 0x1e, 0x7d, 0x28, 0x29, 0x13, 0xf6, 0x51, 0x65,
1443 0x4d, 0x39, 0x85, 0xf0, 0x9d, 0x53, 0xc2, 0xd3, 0xb5, 0x76, 0x3d, 0x7a, 0x72,
1444 0x3b, 0xcb, 0xd6, 0xee, 0x05, 0x3d, 0x5a, 0x40, 0xdd, 0xc5, 0x6e, 0x69, 0x75,
1445 0x13, 0x8c, 0x08, 0x39, 0xe5, 0x80, 0xb5, 0x4d, 0x6d, 0x99, 0x9d, 0xc6, 0x16,
1446 0x84, 0x3c, 0xfe, 0x04, 0x1e, 0x8f, 0x38, 0x8b, 0x12, 0x4e, 0xf7, 0xb5, 0xed,
1447 ],
1448 internal_fp: [
1449 0x82, 0x64, 0xed, 0xec, 0x63, 0xb1, 0x55, 0x00, 0x1d, 0x84, 0x96, 0x68, 0x5c,
1450 0xc7, 0xc2, 0x1e, 0xa9, 0x57, 0xc6, 0xf5, 0x91, 0x09, 0x0a, 0x1c, 0x20, 0xe5,
1451 0x2a, 0x41, 0x89, 0xb8, 0xbb, 0x96,
1452 ],
1453 },
1454 TestVector {
1455 ask: Some([
1456 0xd5, 0xf7, 0xe9, 0x2e, 0xfb, 0x7a, 0xbe, 0x04, 0xdc, 0x8c, 0x14, 0x8b, 0x0b,
1457 0x3b, 0x0f, 0xc2, 0x3e, 0x04, 0x29, 0xf0, 0x02, 0x08, 0xff, 0x93, 0xb6, 0x8d,
1458 0x21, 0xa6, 0xe1, 0x31, 0xbd, 0x04,
1459 ]),
1460 nsk: Some([
1461 0x37, 0x2a, 0x7c, 0x68, 0x22, 0xcb, 0xe6, 0x03, 0xf3, 0x46, 0x5c, 0x4b, 0x9b,
1462 0x65, 0x58, 0xf3, 0xa3, 0x51, 0x2d, 0xec, 0xd4, 0x34, 0x01, 0x2e, 0x67, 0xbf,
1463 0xfc, 0xf6, 0x57, 0xe5, 0x75, 0x0a,
1464 ]),
1465 ovk: [
1466 0x25, 0x30, 0x76, 0x19, 0x33, 0x34, 0x8c, 0x1f, 0xcf, 0x14, 0x35, 0x54, 0x33,
1467 0xa8, 0xd2, 0x91, 0x16, 0x7f, 0xbb, 0x37, 0xb2, 0xce, 0x37, 0xca, 0x97, 0x16,
1468 0x0a, 0x47, 0xec, 0x33, 0x1c, 0x69,
1469 ],
1470 dk: [
1471 0xf2, 0x88, 0x40, 0x0f, 0xd6, 0x5f, 0x9a, 0xdf, 0xe3, 0xa7, 0xc3, 0x72, 0x0a,
1472 0xce, 0xee, 0x0d, 0xae, 0x05, 0x0d, 0x0a, 0x81, 0x9d, 0x61, 0x9f, 0x92, 0xe9,
1473 0xe2, 0xcb, 0x44, 0x34, 0xd5, 0x26,
1474 ],
1475 c: [
1476 0x6f, 0xcc, 0xaa, 0x45, 0xa8, 0x20, 0x6b, 0x06, 0x3e, 0xbb, 0x68, 0xc6, 0x10,
1477 0xe0, 0x59, 0x27, 0xaa, 0x94, 0xd6, 0x1b, 0xe9, 0x3e, 0xc2, 0x5e, 0xb4, 0xf8,
1478 0x2e, 0xfd, 0x68, 0xca, 0xae, 0xdb,
1479 ],
1480 ak: [
1481 0xcf, 0xca, 0x79, 0xd3, 0x37, 0xbc, 0x68, 0x98, 0x13, 0xe4, 0x09, 0xa5, 0x4e,
1482 0x3e, 0x72, 0xad, 0x8e, 0x2f, 0x70, 0x3a, 0xe6, 0xf8, 0x22, 0x3c, 0x9b, 0xec,
1483 0xbd, 0xe9, 0xa8, 0xa3, 0x5f, 0x53,
1484 ],
1485 nk: [
1486 0x51, 0x3d, 0xe6, 0x40, 0x85, 0xd3, 0x5a, 0x3a, 0xdf, 0x23, 0xd8, 0x9d, 0x5a,
1487 0x21, 0xcd, 0xee, 0x4d, 0xb4, 0xc6, 0x25, 0xbd, 0x6a, 0x3c, 0x3c, 0x62, 0x4b,
1488 0xef, 0x43, 0x44, 0x14, 0x1d, 0xeb,
1489 ],
1490 ivk: [
1491 0xf6, 0xe7, 0x5c, 0xd9, 0x80, 0xc3, 0x0e, 0xab, 0xc6, 0x1f, 0x49, 0xac, 0x68,
1492 0xf4, 0x88, 0x57, 0x3a, 0xb3, 0xe6, 0xaf, 0xe1, 0x53, 0x76, 0x37, 0x5d, 0x34,
1493 0xe4, 0x06, 0x70, 0x2f, 0xfd, 0x02,
1494 ],
1495 xsk: Some([
1496 0x01, 0x14, 0xc2, 0x71, 0x3a, 0x01, 0x00, 0x00, 0x80, 0x6f, 0xcc, 0xaa, 0x45,
1497 0xa8, 0x20, 0x6b, 0x06, 0x3e, 0xbb, 0x68, 0xc6, 0x10, 0xe0, 0x59, 0x27, 0xaa,
1498 0x94, 0xd6, 0x1b, 0xe9, 0x3e, 0xc2, 0x5e, 0xb4, 0xf8, 0x2e, 0xfd, 0x68, 0xca,
1499 0xae, 0xdb, 0xd5, 0xf7, 0xe9, 0x2e, 0xfb, 0x7a, 0xbe, 0x04, 0xdc, 0x8c, 0x14,
1500 0x8b, 0x0b, 0x3b, 0x0f, 0xc2, 0x3e, 0x04, 0x29, 0xf0, 0x02, 0x08, 0xff, 0x93,
1501 0xb6, 0x8d, 0x21, 0xa6, 0xe1, 0x31, 0xbd, 0x04, 0x37, 0x2a, 0x7c, 0x68, 0x22,
1502 0xcb, 0xe6, 0x03, 0xf3, 0x46, 0x5c, 0x4b, 0x9b, 0x65, 0x58, 0xf3, 0xa3, 0x51,
1503 0x2d, 0xec, 0xd4, 0x34, 0x01, 0x2e, 0x67, 0xbf, 0xfc, 0xf6, 0x57, 0xe5, 0x75,
1504 0x0a, 0x25, 0x30, 0x76, 0x19, 0x33, 0x34, 0x8c, 0x1f, 0xcf, 0x14, 0x35, 0x54,
1505 0x33, 0xa8, 0xd2, 0x91, 0x16, 0x7f, 0xbb, 0x37, 0xb2, 0xce, 0x37, 0xca, 0x97,
1506 0x16, 0x0a, 0x47, 0xec, 0x33, 0x1c, 0x69, 0xf2, 0x88, 0x40, 0x0f, 0xd6, 0x5f,
1507 0x9a, 0xdf, 0xe3, 0xa7, 0xc3, 0x72, 0x0a, 0xce, 0xee, 0x0d, 0xae, 0x05, 0x0d,
1508 0x0a, 0x81, 0x9d, 0x61, 0x9f, 0x92, 0xe9, 0xe2, 0xcb, 0x44, 0x34, 0xd5, 0x26,
1509 ]),
1510 xfvk: [
1511 0x01, 0x14, 0xc2, 0x71, 0x3a, 0x01, 0x00, 0x00, 0x80, 0x6f, 0xcc, 0xaa, 0x45,
1512 0xa8, 0x20, 0x6b, 0x06, 0x3e, 0xbb, 0x68, 0xc6, 0x10, 0xe0, 0x59, 0x27, 0xaa,
1513 0x94, 0xd6, 0x1b, 0xe9, 0x3e, 0xc2, 0x5e, 0xb4, 0xf8, 0x2e, 0xfd, 0x68, 0xca,
1514 0xae, 0xdb, 0xcf, 0xca, 0x79, 0xd3, 0x37, 0xbc, 0x68, 0x98, 0x13, 0xe4, 0x09,
1515 0xa5, 0x4e, 0x3e, 0x72, 0xad, 0x8e, 0x2f, 0x70, 0x3a, 0xe6, 0xf8, 0x22, 0x3c,
1516 0x9b, 0xec, 0xbd, 0xe9, 0xa8, 0xa3, 0x5f, 0x53, 0x51, 0x3d, 0xe6, 0x40, 0x85,
1517 0xd3, 0x5a, 0x3a, 0xdf, 0x23, 0xd8, 0x9d, 0x5a, 0x21, 0xcd, 0xee, 0x4d, 0xb4,
1518 0xc6, 0x25, 0xbd, 0x6a, 0x3c, 0x3c, 0x62, 0x4b, 0xef, 0x43, 0x44, 0x14, 0x1d,
1519 0xeb, 0x25, 0x30, 0x76, 0x19, 0x33, 0x34, 0x8c, 0x1f, 0xcf, 0x14, 0x35, 0x54,
1520 0x33, 0xa8, 0xd2, 0x91, 0x16, 0x7f, 0xbb, 0x37, 0xb2, 0xce, 0x37, 0xca, 0x97,
1521 0x16, 0x0a, 0x47, 0xec, 0x33, 0x1c, 0x69, 0xf2, 0x88, 0x40, 0x0f, 0xd6, 0x5f,
1522 0x9a, 0xdf, 0xe3, 0xa7, 0xc3, 0x72, 0x0a, 0xce, 0xee, 0x0d, 0xae, 0x05, 0x0d,
1523 0x0a, 0x81, 0x9d, 0x61, 0x9f, 0x92, 0xe9, 0xe2, 0xcb, 0x44, 0x34, 0xd5, 0x26,
1524 ],
1525 fp: [
1526 0x76, 0x84, 0x23, 0xcb, 0x88, 0xd2, 0x2d, 0xee, 0x91, 0xb5, 0xb7, 0x66, 0x1e,
1527 0x72, 0xed, 0x00, 0x95, 0x57, 0xeb, 0xa1, 0x44, 0xc7, 0x8d, 0x1a, 0xa7, 0x1a,
1528 0x3e, 0x88, 0xb6, 0x91, 0x06, 0x96,
1529 ],
1530 d0: None,
1531 d1: Some([
1532 0xbc, 0xc3, 0x23, 0xe8, 0xda, 0x39, 0xb4, 0x96, 0xc0, 0x50, 0x51,
1533 ]),
1534 d2: None,
1535 dmax: Some([
1536 0x25, 0x14, 0x32, 0x0d, 0x33, 0x9c, 0x66, 0x6a, 0x25, 0x4c, 0x06,
1537 ]),
1538 internal_nsk: Some([
1539 0x5d, 0x47, 0x0f, 0x97, 0x79, 0xcc, 0x25, 0x7f, 0x21, 0x28, 0x8f, 0x50, 0x5a,
1540 0x4e, 0x65, 0xb3, 0x8e, 0xb8, 0x53, 0xf1, 0xa2, 0x45, 0x63, 0xb9, 0xf6, 0x74,
1541 0x17, 0x26, 0xf4, 0xd3, 0x01, 0x03,
1542 ]),
1543 internal_ovk: [
1544 0x78, 0x64, 0xe8, 0xc7, 0x9c, 0xea, 0xab, 0x97, 0xe6, 0xae, 0x5b, 0xca, 0x10,
1545 0xf7, 0xd5, 0x1d, 0xf4, 0x20, 0x9a, 0xd0, 0xd4, 0x6e, 0x80, 0xac, 0x18, 0x0d,
1546 0x50, 0xd3, 0xff, 0x09, 0xa6, 0x70,
1547 ],
1548 internal_dk: [
1549 0x54, 0xf1, 0x1e, 0x3f, 0xa3, 0x0d, 0x34, 0xd6, 0xa7, 0x4d, 0xef, 0x1e, 0x6d,
1550 0x5d, 0xaf, 0x58, 0xcf, 0xc7, 0xd7, 0x8b, 0x27, 0xcb, 0x07, 0x15, 0xc1, 0xaf,
1551 0xfa, 0x29, 0xae, 0x39, 0x92, 0xfa,
1552 ],
1553 internal_nk: [
1554 0x31, 0x42, 0x48, 0x75, 0xd6, 0xa5, 0xed, 0x75, 0xde, 0x20, 0x0b, 0xb5, 0xc1,
1555 0xd8, 0x1a, 0xec, 0x4d, 0xff, 0x16, 0x50, 0xb7, 0x8b, 0xb0, 0xca, 0xde, 0x3c,
1556 0x8c, 0x7a, 0xb0, 0x3d, 0xf1, 0x11,
1557 ],
1558 internal_ivk: [
1559 0xe5, 0x42, 0x6b, 0x5b, 0x80, 0xb1, 0x18, 0x67, 0x97, 0x01, 0x65, 0x80, 0xc1,
1560 0xf4, 0x1c, 0x34, 0x19, 0x68, 0x3a, 0xac, 0x77, 0xcf, 0x8d, 0xe0, 0x2f, 0x2f,
1561 0x98, 0x07, 0xd1, 0x50, 0xb4, 0x02,
1562 ],
1563 internal_xsk: Some([
1564 0x01, 0x14, 0xc2, 0x71, 0x3a, 0x01, 0x00, 0x00, 0x80, 0x6f, 0xcc, 0xaa, 0x45,
1565 0xa8, 0x20, 0x6b, 0x06, 0x3e, 0xbb, 0x68, 0xc6, 0x10, 0xe0, 0x59, 0x27, 0xaa,
1566 0x94, 0xd6, 0x1b, 0xe9, 0x3e, 0xc2, 0x5e, 0xb4, 0xf8, 0x2e, 0xfd, 0x68, 0xca,
1567 0xae, 0xdb, 0xd5, 0xf7, 0xe9, 0x2e, 0xfb, 0x7a, 0xbe, 0x04, 0xdc, 0x8c, 0x14,
1568 0x8b, 0x0b, 0x3b, 0x0f, 0xc2, 0x3e, 0x04, 0x29, 0xf0, 0x02, 0x08, 0xff, 0x93,
1569 0xb6, 0x8d, 0x21, 0xa6, 0xe1, 0x31, 0xbd, 0x04, 0x5d, 0x47, 0x0f, 0x97, 0x79,
1570 0xcc, 0x25, 0x7f, 0x21, 0x28, 0x8f, 0x50, 0x5a, 0x4e, 0x65, 0xb3, 0x8e, 0xb8,
1571 0x53, 0xf1, 0xa2, 0x45, 0x63, 0xb9, 0xf6, 0x74, 0x17, 0x26, 0xf4, 0xd3, 0x01,
1572 0x03, 0x78, 0x64, 0xe8, 0xc7, 0x9c, 0xea, 0xab, 0x97, 0xe6, 0xae, 0x5b, 0xca,
1573 0x10, 0xf7, 0xd5, 0x1d, 0xf4, 0x20, 0x9a, 0xd0, 0xd4, 0x6e, 0x80, 0xac, 0x18,
1574 0x0d, 0x50, 0xd3, 0xff, 0x09, 0xa6, 0x70, 0x54, 0xf1, 0x1e, 0x3f, 0xa3, 0x0d,
1575 0x34, 0xd6, 0xa7, 0x4d, 0xef, 0x1e, 0x6d, 0x5d, 0xaf, 0x58, 0xcf, 0xc7, 0xd7,
1576 0x8b, 0x27, 0xcb, 0x07, 0x15, 0xc1, 0xaf, 0xfa, 0x29, 0xae, 0x39, 0x92, 0xfa,
1577 ]),
1578 internal_xfvk: [
1579 0x01, 0x14, 0xc2, 0x71, 0x3a, 0x01, 0x00, 0x00, 0x80, 0x6f, 0xcc, 0xaa, 0x45,
1580 0xa8, 0x20, 0x6b, 0x06, 0x3e, 0xbb, 0x68, 0xc6, 0x10, 0xe0, 0x59, 0x27, 0xaa,
1581 0x94, 0xd6, 0x1b, 0xe9, 0x3e, 0xc2, 0x5e, 0xb4, 0xf8, 0x2e, 0xfd, 0x68, 0xca,
1582 0xae, 0xdb, 0xcf, 0xca, 0x79, 0xd3, 0x37, 0xbc, 0x68, 0x98, 0x13, 0xe4, 0x09,
1583 0xa5, 0x4e, 0x3e, 0x72, 0xad, 0x8e, 0x2f, 0x70, 0x3a, 0xe6, 0xf8, 0x22, 0x3c,
1584 0x9b, 0xec, 0xbd, 0xe9, 0xa8, 0xa3, 0x5f, 0x53, 0x31, 0x42, 0x48, 0x75, 0xd6,
1585 0xa5, 0xed, 0x75, 0xde, 0x20, 0x0b, 0xb5, 0xc1, 0xd8, 0x1a, 0xec, 0x4d, 0xff,
1586 0x16, 0x50, 0xb7, 0x8b, 0xb0, 0xca, 0xde, 0x3c, 0x8c, 0x7a, 0xb0, 0x3d, 0xf1,
1587 0x11, 0x78, 0x64, 0xe8, 0xc7, 0x9c, 0xea, 0xab, 0x97, 0xe6, 0xae, 0x5b, 0xca,
1588 0x10, 0xf7, 0xd5, 0x1d, 0xf4, 0x20, 0x9a, 0xd0, 0xd4, 0x6e, 0x80, 0xac, 0x18,
1589 0x0d, 0x50, 0xd3, 0xff, 0x09, 0xa6, 0x70, 0x54, 0xf1, 0x1e, 0x3f, 0xa3, 0x0d,
1590 0x34, 0xd6, 0xa7, 0x4d, 0xef, 0x1e, 0x6d, 0x5d, 0xaf, 0x58, 0xcf, 0xc7, 0xd7,
1591 0x8b, 0x27, 0xcb, 0x07, 0x15, 0xc1, 0xaf, 0xfa, 0x29, 0xae, 0x39, 0x92, 0xfa,
1592 ],
1593 internal_fp: [
1594 0x12, 0x87, 0xc3, 0x79, 0x02, 0x35, 0x69, 0x16, 0x4e, 0xb5, 0x23, 0xff, 0xdd,
1595 0x72, 0x03, 0x1c, 0x35, 0xe1, 0x85, 0x9f, 0x3e, 0xf8, 0xd4, 0x83, 0x0a, 0x29,
1596 0x91, 0xba, 0x7e, 0x15, 0xde, 0x2d,
1597 ],
1598 },
1599 TestVector {
1600 ask: Some([
1601 0x7f, 0xf3, 0x5d, 0xb6, 0x9e, 0x13, 0xc3, 0x6f, 0x59, 0xad, 0x9c, 0x08, 0xd3,
1602 0x2d, 0x52, 0x27, 0x37, 0x8d, 0xa0, 0xcf, 0xf9, 0x71, 0xfd, 0x42, 0x4b, 0xae,
1603 0xf9, 0xa6, 0x33, 0x2f, 0x51, 0x06,
1604 ]),
1605 nsk: Some([
1606 0x77, 0x9c, 0x6e, 0xe4, 0xa0, 0x39, 0x44, 0xeb, 0xa2, 0x8b, 0xc9, 0xbd, 0xc1,
1607 0x32, 0x9a, 0x39, 0x14, 0x07, 0xf4, 0x8c, 0x41, 0x0d, 0x5a, 0xe0, 0xa3, 0x64,
1608 0xf5, 0x99, 0x59, 0xbf, 0xde, 0x00,
1609 ]),
1610 ovk: [
1611 0xd9, 0xfc, 0x71, 0x01, 0xbf, 0x90, 0x7f, 0x41, 0x88, 0x6a, 0x73, 0x30, 0xa5,
1612 0xd6, 0xa7, 0xbd, 0x23, 0x53, 0x5e, 0x30, 0x5e, 0xb7, 0x67, 0x9b, 0xc2, 0x3d,
1613 0x76, 0x05, 0x93, 0x61, 0x85, 0xac,
1614 ],
1615 dk: [
1616 0xe4, 0x69, 0x9e, 0x9a, 0x86, 0xe0, 0x31, 0xc5, 0x4b, 0x21, 0xcd, 0xd0, 0x96,
1617 0x0a, 0xc1, 0x8d, 0xdd, 0x61, 0xec, 0x9f, 0x7a, 0xe9, 0x8d, 0x55, 0x82, 0xa6,
1618 0xfa, 0xf6, 0x5f, 0x32, 0x48, 0xd1,
1619 ],
1620 c: [
1621 0x44, 0x79, 0x08, 0x6c, 0x75, 0xd0, 0x80, 0x79, 0x60, 0x20, 0xf5, 0x00, 0xc1,
1622 0xe3, 0x0a, 0x54, 0xcf, 0xe2, 0x9d, 0xda, 0x36, 0xf2, 0x14, 0x4f, 0xb3, 0x3a,
1623 0x50, 0x80, 0x6f, 0xbe, 0xf7, 0xda,
1624 ],
1625 ak: [
1626 0x9a, 0x85, 0x3f, 0x95, 0x44, 0x71, 0x37, 0x97, 0xe0, 0x85, 0x17, 0x64, 0xda,
1627 0x39, 0x2e, 0x68, 0x53, 0x4b, 0x1d, 0x94, 0x8d, 0xae, 0x47, 0x42, 0xee, 0x76,
1628 0x5c, 0x72, 0x75, 0x72, 0xab, 0x4e,
1629 ],
1630 nk: [
1631 0xf1, 0x66, 0xa2, 0x8a, 0x4f, 0x88, 0xce, 0xc1, 0x21, 0x41, 0xa8, 0x2d, 0x21,
1632 0x20, 0xbd, 0x6d, 0x8c, 0xaf, 0x87, 0x9c, 0x9a, 0x1b, 0x3a, 0xd2, 0x11, 0x85,
1633 0x01, 0x36, 0x4f, 0x5d, 0x4f, 0xbe,
1634 ],
1635 ivk: [
1636 0x33, 0xbd, 0x46, 0x01, 0x5a, 0x2c, 0xad, 0x17, 0xd6, 0xe0, 0x15, 0xeb, 0x88,
1637 0x86, 0x1b, 0x0c, 0x91, 0x77, 0x96, 0x24, 0x65, 0x70, 0x52, 0x1c, 0x9e, 0x1a,
1638 0xe4, 0xb1, 0xc8, 0x31, 0x1d, 0x06,
1639 ],
1640 xsk: Some([
1641 0x02, 0x76, 0x84, 0x23, 0xcb, 0x02, 0x00, 0x00, 0x80, 0x44, 0x79, 0x08, 0x6c,
1642 0x75, 0xd0, 0x80, 0x79, 0x60, 0x20, 0xf5, 0x00, 0xc1, 0xe3, 0x0a, 0x54, 0xcf,
1643 0xe2, 0x9d, 0xda, 0x36, 0xf2, 0x14, 0x4f, 0xb3, 0x3a, 0x50, 0x80, 0x6f, 0xbe,
1644 0xf7, 0xda, 0x7f, 0xf3, 0x5d, 0xb6, 0x9e, 0x13, 0xc3, 0x6f, 0x59, 0xad, 0x9c,
1645 0x08, 0xd3, 0x2d, 0x52, 0x27, 0x37, 0x8d, 0xa0, 0xcf, 0xf9, 0x71, 0xfd, 0x42,
1646 0x4b, 0xae, 0xf9, 0xa6, 0x33, 0x2f, 0x51, 0x06, 0x77, 0x9c, 0x6e, 0xe4, 0xa0,
1647 0x39, 0x44, 0xeb, 0xa2, 0x8b, 0xc9, 0xbd, 0xc1, 0x32, 0x9a, 0x39, 0x14, 0x07,
1648 0xf4, 0x8c, 0x41, 0x0d, 0x5a, 0xe0, 0xa3, 0x64, 0xf5, 0x99, 0x59, 0xbf, 0xde,
1649 0x00, 0xd9, 0xfc, 0x71, 0x01, 0xbf, 0x90, 0x7f, 0x41, 0x88, 0x6a, 0x73, 0x30,
1650 0xa5, 0xd6, 0xa7, 0xbd, 0x23, 0x53, 0x5e, 0x30, 0x5e, 0xb7, 0x67, 0x9b, 0xc2,
1651 0x3d, 0x76, 0x05, 0x93, 0x61, 0x85, 0xac, 0xe4, 0x69, 0x9e, 0x9a, 0x86, 0xe0,
1652 0x31, 0xc5, 0x4b, 0x21, 0xcd, 0xd0, 0x96, 0x0a, 0xc1, 0x8d, 0xdd, 0x61, 0xec,
1653 0x9f, 0x7a, 0xe9, 0x8d, 0x55, 0x82, 0xa6, 0xfa, 0xf6, 0x5f, 0x32, 0x48, 0xd1,
1654 ]),
1655 xfvk: [
1656 0x02, 0x76, 0x84, 0x23, 0xcb, 0x02, 0x00, 0x00, 0x80, 0x44, 0x79, 0x08, 0x6c,
1657 0x75, 0xd0, 0x80, 0x79, 0x60, 0x20, 0xf5, 0x00, 0xc1, 0xe3, 0x0a, 0x54, 0xcf,
1658 0xe2, 0x9d, 0xda, 0x36, 0xf2, 0x14, 0x4f, 0xb3, 0x3a, 0x50, 0x80, 0x6f, 0xbe,
1659 0xf7, 0xda, 0x9a, 0x85, 0x3f, 0x95, 0x44, 0x71, 0x37, 0x97, 0xe0, 0x85, 0x17,
1660 0x64, 0xda, 0x39, 0x2e, 0x68, 0x53, 0x4b, 0x1d, 0x94, 0x8d, 0xae, 0x47, 0x42,
1661 0xee, 0x76, 0x5c, 0x72, 0x75, 0x72, 0xab, 0x4e, 0xf1, 0x66, 0xa2, 0x8a, 0x4f,
1662 0x88, 0xce, 0xc1, 0x21, 0x41, 0xa8, 0x2d, 0x21, 0x20, 0xbd, 0x6d, 0x8c, 0xaf,
1663 0x87, 0x9c, 0x9a, 0x1b, 0x3a, 0xd2, 0x11, 0x85, 0x01, 0x36, 0x4f, 0x5d, 0x4f,
1664 0xbe, 0xd9, 0xfc, 0x71, 0x01, 0xbf, 0x90, 0x7f, 0x41, 0x88, 0x6a, 0x73, 0x30,
1665 0xa5, 0xd6, 0xa7, 0xbd, 0x23, 0x53, 0x5e, 0x30, 0x5e, 0xb7, 0x67, 0x9b, 0xc2,
1666 0x3d, 0x76, 0x05, 0x93, 0x61, 0x85, 0xac, 0xe4, 0x69, 0x9e, 0x9a, 0x86, 0xe0,
1667 0x31, 0xc5, 0x4b, 0x21, 0xcd, 0xd0, 0x96, 0x0a, 0xc1, 0x8d, 0xdd, 0x61, 0xec,
1668 0x9f, 0x7a, 0xe9, 0x8d, 0x55, 0x82, 0xa6, 0xfa, 0xf6, 0x5f, 0x32, 0x48, 0xd1,
1669 ],
1670 fp: [
1671 0x0b, 0xdc, 0x2d, 0x2b, 0x6e, 0xb1, 0xf9, 0x27, 0xcb, 0xab, 0xdb, 0xb9, 0xd4,
1672 0x3d, 0xb8, 0xde, 0x85, 0x7b, 0xb7, 0x16, 0xdf, 0x86, 0xce, 0xcf, 0x08, 0x1e,
1673 0x1a, 0x2b, 0x74, 0xfc, 0xad, 0x55,
1674 ],
1675 d0: None,
1676 d1: None,
1677 d2: None,
1678 dmax: None,
1679 internal_nsk: Some([
1680 0x7b, 0x17, 0x17, 0x65, 0x27, 0xf9, 0x17, 0x99, 0x0f, 0x9f, 0x51, 0x79, 0xcb,
1681 0x23, 0xc1, 0x6e, 0xc0, 0xa9, 0x26, 0xed, 0xc4, 0x1a, 0xb2, 0xba, 0x42, 0x13,
1682 0x7b, 0xef, 0x5c, 0x20, 0x9f, 0x09,
1683 ]),
1684 internal_ovk: [
1685 0xc6, 0x12, 0xcb, 0xc9, 0x77, 0x30, 0x7e, 0x53, 0x52, 0xa1, 0x58, 0x8b, 0xd7,
1686 0x0f, 0x41, 0xaf, 0x11, 0xe7, 0x3b, 0x7b, 0xc6, 0xbc, 0xbc, 0x73, 0x2a, 0xa3,
1687 0x06, 0xc2, 0x1c, 0xd0, 0x0f, 0x3a,
1688 ],
1689 internal_dk: [
1690 0x35, 0xef, 0x4d, 0x26, 0x59, 0x51, 0xdc, 0xaa, 0xec, 0x26, 0xef, 0x8f, 0xbd,
1691 0xf8, 0x4c, 0x92, 0xb7, 0x90, 0x04, 0x9d, 0x09, 0x93, 0x77, 0x2e, 0xfb, 0x43,
1692 0x97, 0xf0, 0x49, 0x30, 0xf1, 0x67,
1693 ],
1694 internal_nk: [
1695 0x8d, 0x05, 0x55, 0xe8, 0xe0, 0x20, 0xc9, 0xd3, 0x60, 0x68, 0x5d, 0x24, 0x2f,
1696 0x2b, 0xa9, 0xf7, 0x74, 0x61, 0x3f, 0xa0, 0x94, 0x01, 0xf1, 0x25, 0xbc, 0xa9,
1697 0x29, 0xec, 0xa4, 0x86, 0xa3, 0xd1,
1698 ],
1699 internal_ivk: [
1700 0x7f, 0x7c, 0xee, 0xfa, 0x65, 0x42, 0x8e, 0x8b, 0x70, 0x76, 0x19, 0x1a, 0x23,
1701 0x93, 0x95, 0x7b, 0x9c, 0x09, 0x50, 0x61, 0xd8, 0xcc, 0xe1, 0x28, 0x3d, 0xd1,
1702 0x5c, 0x2b, 0x5e, 0x8f, 0xc3, 0x05,
1703 ],
1704 internal_xsk: Some([
1705 0x02, 0x76, 0x84, 0x23, 0xcb, 0x02, 0x00, 0x00, 0x80, 0x44, 0x79, 0x08, 0x6c,
1706 0x75, 0xd0, 0x80, 0x79, 0x60, 0x20, 0xf5, 0x00, 0xc1, 0xe3, 0x0a, 0x54, 0xcf,
1707 0xe2, 0x9d, 0xda, 0x36, 0xf2, 0x14, 0x4f, 0xb3, 0x3a, 0x50, 0x80, 0x6f, 0xbe,
1708 0xf7, 0xda, 0x7f, 0xf3, 0x5d, 0xb6, 0x9e, 0x13, 0xc3, 0x6f, 0x59, 0xad, 0x9c,
1709 0x08, 0xd3, 0x2d, 0x52, 0x27, 0x37, 0x8d, 0xa0, 0xcf, 0xf9, 0x71, 0xfd, 0x42,
1710 0x4b, 0xae, 0xf9, 0xa6, 0x33, 0x2f, 0x51, 0x06, 0x7b, 0x17, 0x17, 0x65, 0x27,
1711 0xf9, 0x17, 0x99, 0x0f, 0x9f, 0x51, 0x79, 0xcb, 0x23, 0xc1, 0x6e, 0xc0, 0xa9,
1712 0x26, 0xed, 0xc4, 0x1a, 0xb2, 0xba, 0x42, 0x13, 0x7b, 0xef, 0x5c, 0x20, 0x9f,
1713 0x09, 0xc6, 0x12, 0xcb, 0xc9, 0x77, 0x30, 0x7e, 0x53, 0x52, 0xa1, 0x58, 0x8b,
1714 0xd7, 0x0f, 0x41, 0xaf, 0x11, 0xe7, 0x3b, 0x7b, 0xc6, 0xbc, 0xbc, 0x73, 0x2a,
1715 0xa3, 0x06, 0xc2, 0x1c, 0xd0, 0x0f, 0x3a, 0x35, 0xef, 0x4d, 0x26, 0x59, 0x51,
1716 0xdc, 0xaa, 0xec, 0x26, 0xef, 0x8f, 0xbd, 0xf8, 0x4c, 0x92, 0xb7, 0x90, 0x04,
1717 0x9d, 0x09, 0x93, 0x77, 0x2e, 0xfb, 0x43, 0x97, 0xf0, 0x49, 0x30, 0xf1, 0x67,
1718 ]),
1719 internal_xfvk: [
1720 0x02, 0x76, 0x84, 0x23, 0xcb, 0x02, 0x00, 0x00, 0x80, 0x44, 0x79, 0x08, 0x6c,
1721 0x75, 0xd0, 0x80, 0x79, 0x60, 0x20, 0xf5, 0x00, 0xc1, 0xe3, 0x0a, 0x54, 0xcf,
1722 0xe2, 0x9d, 0xda, 0x36, 0xf2, 0x14, 0x4f, 0xb3, 0x3a, 0x50, 0x80, 0x6f, 0xbe,
1723 0xf7, 0xda, 0x9a, 0x85, 0x3f, 0x95, 0x44, 0x71, 0x37, 0x97, 0xe0, 0x85, 0x17,
1724 0x64, 0xda, 0x39, 0x2e, 0x68, 0x53, 0x4b, 0x1d, 0x94, 0x8d, 0xae, 0x47, 0x42,
1725 0xee, 0x76, 0x5c, 0x72, 0x75, 0x72, 0xab, 0x4e, 0x8d, 0x05, 0x55, 0xe8, 0xe0,
1726 0x20, 0xc9, 0xd3, 0x60, 0x68, 0x5d, 0x24, 0x2f, 0x2b, 0xa9, 0xf7, 0x74, 0x61,
1727 0x3f, 0xa0, 0x94, 0x01, 0xf1, 0x25, 0xbc, 0xa9, 0x29, 0xec, 0xa4, 0x86, 0xa3,
1728 0xd1, 0xc6, 0x12, 0xcb, 0xc9, 0x77, 0x30, 0x7e, 0x53, 0x52, 0xa1, 0x58, 0x8b,
1729 0xd7, 0x0f, 0x41, 0xaf, 0x11, 0xe7, 0x3b, 0x7b, 0xc6, 0xbc, 0xbc, 0x73, 0x2a,
1730 0xa3, 0x06, 0xc2, 0x1c, 0xd0, 0x0f, 0x3a, 0x35, 0xef, 0x4d, 0x26, 0x59, 0x51,
1731 0xdc, 0xaa, 0xec, 0x26, 0xef, 0x8f, 0xbd, 0xf8, 0x4c, 0x92, 0xb7, 0x90, 0x04,
1732 0x9d, 0x09, 0x93, 0x77, 0x2e, 0xfb, 0x43, 0x97, 0xf0, 0x49, 0x30, 0xf1, 0x67,
1733 ],
1734 internal_fp: [
1735 0xe0, 0xba, 0xa5, 0xdb, 0xb8, 0x06, 0xc7, 0x21, 0x33, 0x3c, 0x63, 0x08, 0x34,
1736 0x5f, 0xc5, 0x1c, 0x2d, 0xc1, 0xe0, 0x09, 0xda, 0x04, 0x47, 0x78, 0xa3, 0xc3,
1737 0x29, 0x4d, 0x68, 0x17, 0xa3, 0xc4,
1738 ],
1739 },
1740 TestVector {
1741 ask: Some([
1742 0x45, 0x93, 0xd2, 0x4d, 0x21, 0xe3, 0x59, 0x37, 0xf1, 0x52, 0xcf, 0x90, 0x46,
1743 0x1c, 0x33, 0x2f, 0x69, 0x50, 0x3c, 0x10, 0x45, 0x81, 0xd6, 0x83, 0xe0, 0xac,
1744 0x29, 0xf8, 0x4d, 0xec, 0xaf, 0x07,
1745 ]),
1746 nsk: Some([
1747 0x1a, 0xc8, 0x7e, 0xc2, 0x12, 0x3f, 0x50, 0x57, 0xe3, 0xc0, 0xf8, 0x58, 0xe8,
1748 0x0d, 0xfa, 0x0e, 0xe4, 0x55, 0x3d, 0xed, 0x27, 0xb7, 0xb5, 0xab, 0xfb, 0xb6,
1749 0xfa, 0x6e, 0xff, 0xa7, 0xbb, 0x0b,
1750 ]),
1751 ovk: [
1752 0x1e, 0x36, 0xea, 0x0c, 0xf2, 0xbe, 0x2e, 0x9d, 0x6c, 0xe3, 0x80, 0xa8, 0xaf,
1753 0x18, 0xe7, 0x5d, 0xa9, 0x22, 0x55, 0x51, 0xfb, 0xef, 0x8b, 0x98, 0x31, 0x1b,
1754 0x5c, 0x9c, 0x1b, 0x4b, 0x9e, 0xe3,
1755 ],
1756 dk: [
1757 0x57, 0xfc, 0x6c, 0x59, 0xa4, 0xf3, 0xad, 0x5a, 0x6f, 0x60, 0x9d, 0xb6, 0x71,
1758 0xd2, 0x8c, 0xbf, 0x70, 0x3f, 0x0d, 0x14, 0xdc, 0x36, 0x3a, 0xaa, 0xed, 0x70,
1759 0x72, 0x9c, 0x10, 0x7b, 0xbb, 0x6a,
1760 ],
1761 c: [
1762 0x33, 0xdc, 0x01, 0x2d, 0x76, 0x90, 0xce, 0xd2, 0xcd, 0x2b, 0xcb, 0x2c, 0xc3,
1763 0xe4, 0x63, 0xe2, 0x8d, 0x8c, 0x29, 0xef, 0x3b, 0x01, 0xbe, 0x59, 0xb2, 0xbd,
1764 0xfc, 0x38, 0x5b, 0xbd, 0xc7, 0x4b,
1765 ],
1766 ak: [
1767 0x9c, 0x6d, 0x85, 0x9a, 0x75, 0x2c, 0x30, 0x5d, 0x62, 0x63, 0xde, 0x95, 0xf2,
1768 0xfc, 0xf7, 0x34, 0xb1, 0x26, 0xdf, 0x24, 0x56, 0xc7, 0xd3, 0x1b, 0xc6, 0x01,
1769 0xc8, 0xdd, 0xec, 0x40, 0x91, 0x12,
1770 ],
1771 nk: [
1772 0xd3, 0xee, 0x41, 0xf8, 0x4b, 0x5a, 0x95, 0x08, 0xb6, 0x1d, 0x29, 0xb2, 0xfb,
1773 0x45, 0x63, 0x6d, 0x19, 0xaa, 0x10, 0xd7, 0x82, 0xcd, 0x97, 0x8c, 0xfe, 0x67,
1774 0x15, 0x49, 0x2f, 0xcd, 0x22, 0x4e,
1775 ],
1776 ivk: [
1777 0xd1, 0x38, 0xe1, 0x37, 0xc6, 0x67, 0x1d, 0xe7, 0x82, 0xfb, 0x01, 0xba, 0x91,
1778 0x1d, 0x98, 0x64, 0xbe, 0xbc, 0x44, 0x36, 0xcc, 0xb3, 0x88, 0xb4, 0xc1, 0xce,
1779 0x02, 0x56, 0xa8, 0xdb, 0x74, 0x01,
1780 ],
1781 xsk: Some([
1782 0x03, 0x0b, 0xdc, 0x2d, 0x2b, 0x03, 0x00, 0x00, 0x80, 0x33, 0xdc, 0x01, 0x2d,
1783 0x76, 0x90, 0xce, 0xd2, 0xcd, 0x2b, 0xcb, 0x2c, 0xc3, 0xe4, 0x63, 0xe2, 0x8d,
1784 0x8c, 0x29, 0xef, 0x3b, 0x01, 0xbe, 0x59, 0xb2, 0xbd, 0xfc, 0x38, 0x5b, 0xbd,
1785 0xc7, 0x4b, 0x45, 0x93, 0xd2, 0x4d, 0x21, 0xe3, 0x59, 0x37, 0xf1, 0x52, 0xcf,
1786 0x90, 0x46, 0x1c, 0x33, 0x2f, 0x69, 0x50, 0x3c, 0x10, 0x45, 0x81, 0xd6, 0x83,
1787 0xe0, 0xac, 0x29, 0xf8, 0x4d, 0xec, 0xaf, 0x07, 0x1a, 0xc8, 0x7e, 0xc2, 0x12,
1788 0x3f, 0x50, 0x57, 0xe3, 0xc0, 0xf8, 0x58, 0xe8, 0x0d, 0xfa, 0x0e, 0xe4, 0x55,
1789 0x3d, 0xed, 0x27, 0xb7, 0xb5, 0xab, 0xfb, 0xb6, 0xfa, 0x6e, 0xff, 0xa7, 0xbb,
1790 0x0b, 0x1e, 0x36, 0xea, 0x0c, 0xf2, 0xbe, 0x2e, 0x9d, 0x6c, 0xe3, 0x80, 0xa8,
1791 0xaf, 0x18, 0xe7, 0x5d, 0xa9, 0x22, 0x55, 0x51, 0xfb, 0xef, 0x8b, 0x98, 0x31,
1792 0x1b, 0x5c, 0x9c, 0x1b, 0x4b, 0x9e, 0xe3, 0x57, 0xfc, 0x6c, 0x59, 0xa4, 0xf3,
1793 0xad, 0x5a, 0x6f, 0x60, 0x9d, 0xb6, 0x71, 0xd2, 0x8c, 0xbf, 0x70, 0x3f, 0x0d,
1794 0x14, 0xdc, 0x36, 0x3a, 0xaa, 0xed, 0x70, 0x72, 0x9c, 0x10, 0x7b, 0xbb, 0x6a,
1795 ]),
1796 xfvk: [
1797 0x03, 0x0b, 0xdc, 0x2d, 0x2b, 0x03, 0x00, 0x00, 0x80, 0x33, 0xdc, 0x01, 0x2d,
1798 0x76, 0x90, 0xce, 0xd2, 0xcd, 0x2b, 0xcb, 0x2c, 0xc3, 0xe4, 0x63, 0xe2, 0x8d,
1799 0x8c, 0x29, 0xef, 0x3b, 0x01, 0xbe, 0x59, 0xb2, 0xbd, 0xfc, 0x38, 0x5b, 0xbd,
1800 0xc7, 0x4b, 0x9c, 0x6d, 0x85, 0x9a, 0x75, 0x2c, 0x30, 0x5d, 0x62, 0x63, 0xde,
1801 0x95, 0xf2, 0xfc, 0xf7, 0x34, 0xb1, 0x26, 0xdf, 0x24, 0x56, 0xc7, 0xd3, 0x1b,
1802 0xc6, 0x01, 0xc8, 0xdd, 0xec, 0x40, 0x91, 0x12, 0xd3, 0xee, 0x41, 0xf8, 0x4b,
1803 0x5a, 0x95, 0x08, 0xb6, 0x1d, 0x29, 0xb2, 0xfb, 0x45, 0x63, 0x6d, 0x19, 0xaa,
1804 0x10, 0xd7, 0x82, 0xcd, 0x97, 0x8c, 0xfe, 0x67, 0x15, 0x49, 0x2f, 0xcd, 0x22,
1805 0x4e, 0x1e, 0x36, 0xea, 0x0c, 0xf2, 0xbe, 0x2e, 0x9d, 0x6c, 0xe3, 0x80, 0xa8,
1806 0xaf, 0x18, 0xe7, 0x5d, 0xa9, 0x22, 0x55, 0x51, 0xfb, 0xef, 0x8b, 0x98, 0x31,
1807 0x1b, 0x5c, 0x9c, 0x1b, 0x4b, 0x9e, 0xe3, 0x57, 0xfc, 0x6c, 0x59, 0xa4, 0xf3,
1808 0xad, 0x5a, 0x6f, 0x60, 0x9d, 0xb6, 0x71, 0xd2, 0x8c, 0xbf, 0x70, 0x3f, 0x0d,
1809 0x14, 0xdc, 0x36, 0x3a, 0xaa, 0xed, 0x70, 0x72, 0x9c, 0x10, 0x7b, 0xbb, 0x6a,
1810 ],
1811 fp: [
1812 0xdf, 0x0a, 0x89, 0xbd, 0x88, 0x35, 0x39, 0xc0, 0x7b, 0x89, 0xe0, 0x4c, 0x92,
1813 0x76, 0x4e, 0xc2, 0xd1, 0x59, 0x69, 0x0f, 0x5a, 0xd5, 0xdd, 0x3d, 0x0a, 0xd8,
1814 0xac, 0x29, 0x69, 0xde, 0x22, 0xc8,
1815 ],
1816 d0: None,
1817 d1: None,
1818 d2: None,
1819 dmax: Some([
1820 0xb8, 0x31, 0xc2, 0x96, 0x5a, 0x86, 0x0a, 0xd7, 0x60, 0xec, 0x2a,
1821 ]),
1822 internal_nsk: Some([
1823 0x9c, 0x39, 0x3c, 0x5b, 0xd7, 0x66, 0x4d, 0x63, 0xef, 0xa1, 0xba, 0xea, 0x99,
1824 0xfc, 0x6d, 0xc4, 0x74, 0xfe, 0xa7, 0x53, 0xce, 0x84, 0xc8, 0x81, 0xd9, 0xef,
1825 0x28, 0x77, 0x86, 0x75, 0xb1, 0x05,
1826 ]),
1827 internal_ovk: [
1828 0x69, 0xaa, 0xb0, 0x2e, 0xa6, 0x43, 0x57, 0x9d, 0x4d, 0x85, 0x2a, 0xf8, 0xb4,
1829 0x32, 0xb8, 0x8d, 0x1c, 0xa0, 0x00, 0x44, 0x4a, 0xb0, 0x73, 0x7a, 0x41, 0x15,
1830 0xe0, 0x63, 0xf1, 0x48, 0xd2, 0x72,
1831 ],
1832 internal_dk: [
1833 0x88, 0x26, 0xa9, 0x3c, 0x65, 0xc6, 0x6e, 0x75, 0x54, 0x32, 0x74, 0xe6, 0x72,
1834 0xad, 0xf5, 0x59, 0xf7, 0xd7, 0x26, 0x5e, 0x99, 0xcc, 0x11, 0xda, 0x4a, 0x14,
1835 0x20, 0xa3, 0x7b, 0x92, 0xf7, 0xab,
1836 ],
1837 internal_nk: [
1838 0x59, 0xba, 0xa9, 0x0f, 0x83, 0x4a, 0x66, 0x1b, 0xf2, 0xbe, 0x42, 0x46, 0xa4,
1839 0x3d, 0x18, 0x9c, 0x7d, 0x0e, 0x17, 0xa8, 0x24, 0x7b, 0x4f, 0xd9, 0xd2, 0xe1,
1840 0x53, 0xa5, 0x97, 0x3d, 0xc8, 0xec,
1841 ],
1842 internal_ivk: [
1843 0x8a, 0x86, 0xfb, 0x27, 0x81, 0xfe, 0x6f, 0x24, 0xd9, 0x60, 0xdd, 0xdb, 0x2f,
1844 0x78, 0x13, 0xc0, 0x31, 0xfe, 0xc5, 0x5d, 0x26, 0xcc, 0xde, 0xe1, 0xf7, 0x18,
1845 0x2a, 0x3e, 0xc6, 0x83, 0xcf, 0x04,
1846 ],
1847 internal_xsk: Some([
1848 0x03, 0x0b, 0xdc, 0x2d, 0x2b, 0x03, 0x00, 0x00, 0x80, 0x33, 0xdc, 0x01, 0x2d,
1849 0x76, 0x90, 0xce, 0xd2, 0xcd, 0x2b, 0xcb, 0x2c, 0xc3, 0xe4, 0x63, 0xe2, 0x8d,
1850 0x8c, 0x29, 0xef, 0x3b, 0x01, 0xbe, 0x59, 0xb2, 0xbd, 0xfc, 0x38, 0x5b, 0xbd,
1851 0xc7, 0x4b, 0x45, 0x93, 0xd2, 0x4d, 0x21, 0xe3, 0x59, 0x37, 0xf1, 0x52, 0xcf,
1852 0x90, 0x46, 0x1c, 0x33, 0x2f, 0x69, 0x50, 0x3c, 0x10, 0x45, 0x81, 0xd6, 0x83,
1853 0xe0, 0xac, 0x29, 0xf8, 0x4d, 0xec, 0xaf, 0x07, 0x9c, 0x39, 0x3c, 0x5b, 0xd7,
1854 0x66, 0x4d, 0x63, 0xef, 0xa1, 0xba, 0xea, 0x99, 0xfc, 0x6d, 0xc4, 0x74, 0xfe,
1855 0xa7, 0x53, 0xce, 0x84, 0xc8, 0x81, 0xd9, 0xef, 0x28, 0x77, 0x86, 0x75, 0xb1,
1856 0x05, 0x69, 0xaa, 0xb0, 0x2e, 0xa6, 0x43, 0x57, 0x9d, 0x4d, 0x85, 0x2a, 0xf8,
1857 0xb4, 0x32, 0xb8, 0x8d, 0x1c, 0xa0, 0x00, 0x44, 0x4a, 0xb0, 0x73, 0x7a, 0x41,
1858 0x15, 0xe0, 0x63, 0xf1, 0x48, 0xd2, 0x72, 0x88, 0x26, 0xa9, 0x3c, 0x65, 0xc6,
1859 0x6e, 0x75, 0x54, 0x32, 0x74, 0xe6, 0x72, 0xad, 0xf5, 0x59, 0xf7, 0xd7, 0x26,
1860 0x5e, 0x99, 0xcc, 0x11, 0xda, 0x4a, 0x14, 0x20, 0xa3, 0x7b, 0x92, 0xf7, 0xab,
1861 ]),
1862 internal_xfvk: [
1863 0x03, 0x0b, 0xdc, 0x2d, 0x2b, 0x03, 0x00, 0x00, 0x80, 0x33, 0xdc, 0x01, 0x2d,
1864 0x76, 0x90, 0xce, 0xd2, 0xcd, 0x2b, 0xcb, 0x2c, 0xc3, 0xe4, 0x63, 0xe2, 0x8d,
1865 0x8c, 0x29, 0xef, 0x3b, 0x01, 0xbe, 0x59, 0xb2, 0xbd, 0xfc, 0x38, 0x5b, 0xbd,
1866 0xc7, 0x4b, 0x9c, 0x6d, 0x85, 0x9a, 0x75, 0x2c, 0x30, 0x5d, 0x62, 0x63, 0xde,
1867 0x95, 0xf2, 0xfc, 0xf7, 0x34, 0xb1, 0x26, 0xdf, 0x24, 0x56, 0xc7, 0xd3, 0x1b,
1868 0xc6, 0x01, 0xc8, 0xdd, 0xec, 0x40, 0x91, 0x12, 0x59, 0xba, 0xa9, 0x0f, 0x83,
1869 0x4a, 0x66, 0x1b, 0xf2, 0xbe, 0x42, 0x46, 0xa4, 0x3d, 0x18, 0x9c, 0x7d, 0x0e,
1870 0x17, 0xa8, 0x24, 0x7b, 0x4f, 0xd9, 0xd2, 0xe1, 0x53, 0xa5, 0x97, 0x3d, 0xc8,
1871 0xec, 0x69, 0xaa, 0xb0, 0x2e, 0xa6, 0x43, 0x57, 0x9d, 0x4d, 0x85, 0x2a, 0xf8,
1872 0xb4, 0x32, 0xb8, 0x8d, 0x1c, 0xa0, 0x00, 0x44, 0x4a, 0xb0, 0x73, 0x7a, 0x41,
1873 0x15, 0xe0, 0x63, 0xf1, 0x48, 0xd2, 0x72, 0x88, 0x26, 0xa9, 0x3c, 0x65, 0xc6,
1874 0x6e, 0x75, 0x54, 0x32, 0x74, 0xe6, 0x72, 0xad, 0xf5, 0x59, 0xf7, 0xd7, 0x26,
1875 0x5e, 0x99, 0xcc, 0x11, 0xda, 0x4a, 0x14, 0x20, 0xa3, 0x7b, 0x92, 0xf7, 0xab,
1876 ],
1877 internal_fp: [
1878 0x3f, 0x63, 0x16, 0x1d, 0x5b, 0x43, 0x72, 0x04, 0xf7, 0x01, 0x2a, 0x3a, 0x1d,
1879 0x36, 0x58, 0x1d, 0xab, 0x39, 0x7a, 0x84, 0x3b, 0x2c, 0x58, 0x98, 0x11, 0xed,
1880 0xcc, 0x5b, 0x50, 0x1c, 0xd4, 0xeb,
1881 ],
1882 },
1883 ];
1884
1885 let seed = [
1886 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
1887 24, 25, 26, 27, 28, 29, 30, 31,
1888 ];
1889
1890 let i1h = ChildIndex::hardened(1);
1891 let i2h = ChildIndex::hardened(2);
1892 let i3h = ChildIndex::hardened(3);
1893
1894 let m = ExtendedSpendingKey::master(&seed).unwrap();
1895 let m_1h = m.derive_child(i1h).unwrap();
1896 let m_1h_2h = ExtendedSpendingKey::from_path(&m, &[i1h, i2h]).unwrap();
1897 let m_1h_2h_3h = m_1h_2h.derive_child(i3h).unwrap();
1898
1899 let xfvks = [
1900 m.to_extended_full_viewing_key(),
1901 m_1h.to_extended_full_viewing_key(),
1902 m_1h_2h.to_extended_full_viewing_key(),
1903 m_1h_2h_3h.to_extended_full_viewing_key(),
1904 ];
1905 assert_eq!(test_vectors.len(), xfvks.len());
1906
1907 let xsks = [m, m_1h, m_1h_2h, m_1h_2h_3h];
1908
1909 for (xsk, tv) in xsks.iter().zip(test_vectors.iter()) {
1910 assert_eq!(xsk.expsk.ask().to_bytes(), tv.ask.unwrap());
1911 assert_eq!(xsk.expsk.nsk().to_repr().as_ref(), tv.nsk.unwrap());
1912
1913 assert_eq!(xsk.expsk.ovk().0, tv.ovk);
1914 assert_eq!(xsk.dk.0, tv.dk);
1915 assert_eq!(xsk.chain_code.as_bytes(), &tv.c);
1916
1917 let mut ser = vec![];
1918 xsk.write(&mut ser).unwrap();
1919 assert_eq!(&ser[..], &tv.xsk.unwrap()[..]);
1920
1921 let internal_xsk = xsk.derive_internal().unwrap();
1922 assert_eq!(internal_xsk.expsk.ask().to_bytes(), tv.ask.unwrap());
1923 assert_eq!(
1924 internal_xsk.expsk.nsk().to_repr().as_ref(),
1925 tv.internal_nsk.unwrap()
1926 );
1927
1928 assert_eq!(internal_xsk.expsk.ovk().0, tv.internal_ovk);
1929 assert_eq!(internal_xsk.dk.0, tv.internal_dk);
1930 assert_eq!(internal_xsk.chain_code.as_bytes(), &tv.c);
1931
1932 let mut ser = vec![];
1933 internal_xsk.write(&mut ser).unwrap();
1934 assert_eq!(&ser[..], &tv.internal_xsk.unwrap()[..]);
1935 }
1936
1937 for (xfvk, tv) in xfvks.iter().zip(test_vectors.iter()) {
1938 assert_eq!(xfvk.fvk.vk.ak().to_bytes(), tv.ak);
1939 assert_eq!(xfvk.fvk.vk.nk().0.to_bytes(), tv.nk);
1940
1941 assert_eq!(xfvk.fvk.ovk.0, tv.ovk);
1942 assert_eq!(xfvk.dk.0, tv.dk);
1943 assert_eq!(xfvk.chain_code.as_bytes(), &tv.c);
1944
1945 assert_eq!(xfvk.fvk.vk.ivk().to_repr().as_ref(), tv.ivk);
1946
1947 let mut ser = vec![];
1948 xfvk.write(&mut ser).unwrap();
1949 assert_eq!(&ser[..], &tv.xfvk[..]);
1950 assert_eq!(FvkFingerprint::from(&xfvk.fvk).0, tv.fp);
1951
1952 let mut di = DiversifierIndex::new();
1954 match xfvk.dk.find_diversifier(di).unwrap() {
1955 (l, d) if l == di => assert_eq!(d.0, tv.d0.unwrap()),
1956 (_, _) => assert!(tv.d0.is_none()),
1957 }
1958
1959 di.increment().unwrap();
1961 match xfvk.dk.find_diversifier(di).unwrap() {
1962 (l, d) if l == di => assert_eq!(d.0, tv.d1.unwrap()),
1963 (_, _) => assert!(tv.d1.is_none()),
1964 }
1965
1966 di.increment().unwrap();
1968 match xfvk.dk.find_diversifier(di).unwrap() {
1969 (l, d) if l == di => assert_eq!(d.0, tv.d2.unwrap()),
1970 (_, _) => assert!(tv.d2.is_none()),
1971 }
1972
1973 let dmax = DiversifierIndex::from([0xff; 11]);
1975 match xfvk.dk.find_diversifier(dmax) {
1976 Some((l, d)) if l == dmax => assert_eq!(d.0, tv.dmax.unwrap()),
1977 Some((_, _)) => panic!(),
1978 None => assert!(tv.dmax.is_none()),
1979 }
1980
1981 let internal_xfvk = xfvk.derive_internal().unwrap();
1982 assert_eq!(internal_xfvk.fvk.vk.ak().to_bytes(), tv.ak);
1983 assert_eq!(internal_xfvk.fvk.vk.nk().0.to_bytes(), tv.internal_nk);
1984
1985 assert_eq!(internal_xfvk.fvk.ovk.0, tv.internal_ovk);
1986 assert_eq!(internal_xfvk.dk.0, tv.internal_dk);
1987 assert_eq!(internal_xfvk.chain_code.as_bytes(), &tv.c);
1988
1989 assert_eq!(
1990 internal_xfvk.fvk.vk.ivk().to_repr().as_ref(),
1991 tv.internal_ivk
1992 );
1993
1994 let mut ser = vec![];
1995 internal_xfvk.write(&mut ser).unwrap();
1996 assert_eq!(&ser[..], &tv.internal_xfvk[..]);
1997 assert_eq!(FvkFingerprint::from(&internal_xfvk.fvk).0, tv.internal_fp);
1998
1999 let dfvk = xfvk.to_diversifiable_full_viewing_key();
2000 let ivk = dfvk.to_external_ivk();
2001 let ivk_bytes = ivk.to_bytes();
2002 assert_eq!(&ivk_bytes[..32], tv.dk);
2003 assert_eq!(&ivk_bytes[32..], tv.ivk);
2004
2005 let ivk_rt = IncomingViewingKey::from_bytes(&ivk_bytes).unwrap();
2006 assert_eq!(ivk.dk, ivk_rt.dk);
2007 assert_eq!(ivk.ivk, ivk_rt.ivk);
2008 }
2009 }
2010}
2011
2012#[cfg(any(test, feature = "test-dependencies"))]
2013#[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))]
2014pub mod testing {
2015 use proptest::collection::vec;
2016 use proptest::prelude::{any, prop_compose, Strategy};
2017
2018 use super::ExtendedSpendingKey;
2019
2020 prop_compose! {
2021 pub fn arb_extended_spending_key()(
2022 xsk in vec(any::<u8>(), 32..252).prop_filter_map(
2023 "master key must be valid",
2024 |seed| ExtendedSpendingKey::master(&seed),
2025 )
2026 ) -> ExtendedSpendingKey {
2027 xsk
2028 }
2029 }
2030}
2031
2032#[cfg(all(test, feature = "zeroize"))]
2033mod zeroize_tests {
2034 use zeroize::Zeroize;
2035
2036 use super::ExtendedSpendingKey;
2037
2038 #[test]
2039 fn extended_spending_key_zeroizes() {
2040 let mut xsk = ExtendedSpendingKey::master(&[7; 32]).unwrap();
2041 let before = xsk.to_bytes();
2042 assert_ne!(&before[9..], &[0u8; 160][..]);
2043
2044 xsk.zeroize();
2045 let after = xsk.to_bytes();
2046 assert_eq!(&after[..9], &before[..9]);
2048 assert_eq!(&after[9..], &[0u8; 160][..]);
2049 }
2050}