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