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