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