1use alloc::vec::Vec;
8use core::fmt;
9use core2::io::{self, Read, Write};
10
11use super::{
12 address::PaymentAddress,
13 constants::{self, PROOF_GENERATION_KEY_GENERATOR},
14 note_encryption::KDF_SAPLING_PERSONALIZATION,
15 spec::{
16 crh_ivk, diversify_hash, ka_sapling_agree, ka_sapling_agree_prepared,
17 ka_sapling_derive_public, ka_sapling_derive_public_subgroup_prepared, PreparedBase,
18 PreparedBaseSubgroup, PreparedScalar,
19 },
20};
21
22use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
23use ff::{Field, PrimeField};
24use group::{Curve, Group, GroupEncoding};
25use redjubjub::SpendAuth;
26use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
27use zcash_note_encryption::EphemeralKeyBytes;
28use zcash_spec::PrfExpand;
29
30#[cfg(all(feature = "circuit", test))]
31use rand_core::RngCore;
32
33pub enum DecodingError {
35 LengthInvalid { expected: usize, actual: usize },
37 InvalidAsk,
39 InvalidNsk,
41 UnsupportedChildIndex,
44}
45
46#[derive(Clone, Debug)]
52pub struct SpendAuthorizingKey(redjubjub::SigningKey<SpendAuth>);
53
54impl PartialEq for SpendAuthorizingKey {
55 fn eq(&self, other: &Self) -> bool {
56 <[u8; 32]>::from(self.0)
57 .ct_eq(&<[u8; 32]>::from(other.0))
58 .into()
59 }
60}
61
62impl Eq for SpendAuthorizingKey {}
63
64impl From<&SpendValidatingKey> for jubjub::ExtendedPoint {
65 fn from(spend_validating_key: &SpendValidatingKey) -> jubjub::ExtendedPoint {
66 jubjub::ExtendedPoint::from_bytes(&spend_validating_key.to_bytes()).unwrap()
67 }
68}
69
70impl SpendAuthorizingKey {
71 fn derive_inner(sk: &[u8]) -> jubjub::Scalar {
73 jubjub::Scalar::from_bytes_wide(&PrfExpand::SAPLING_ASK.with(sk))
74 }
75
76 pub(crate) fn from_scalar(ask: jubjub::Scalar) -> Option<Self> {
78 if ask.is_zero().into() {
79 None
80 } else {
81 Some(SpendAuthorizingKey(ask.to_bytes().try_into().unwrap()))
82 }
83 }
84
85 fn from_spending_key(sk: &[u8]) -> Option<Self> {
87 Self::from_scalar(Self::derive_inner(sk))
88 }
89
90 pub(crate) fn from_bytes(bytes: &[u8]) -> Option<Self> {
92 <[u8; 32]>::try_from(bytes)
93 .ok()
94 .and_then(|b| {
95 jubjub::Scalar::from_repr(b)
99 .and_then(|s| {
100 CtOption::new(
101 redjubjub::SigningKey::try_from(b)
102 .expect("RedJubjub permits the set of valid SpendAuthorizingKeys"),
103 !s.is_zero(),
104 )
105 })
106 .into()
107 })
108 .map(SpendAuthorizingKey)
109 }
110
111 pub fn to_bytes(&self) -> [u8; 32] {
113 <[u8; 32]>::from(self.0)
114 }
115
116 pub(crate) fn to_scalar(&self) -> jubjub::Scalar {
120 jubjub::Scalar::from_repr(self.0.into()).unwrap()
121 }
122
123 pub fn randomize(&self, randomizer: &jubjub::Scalar) -> redjubjub::SigningKey<SpendAuth> {
127 self.0.randomize(randomizer)
128 }
129}
130
131#[derive(Clone, Debug)]
137pub struct SpendValidatingKey(redjubjub::VerificationKey<SpendAuth>);
138
139impl From<&SpendAuthorizingKey> for SpendValidatingKey {
140 fn from(ask: &SpendAuthorizingKey) -> Self {
141 SpendValidatingKey((&ask.0).into())
142 }
143}
144
145impl PartialEq for SpendValidatingKey {
146 fn eq(&self, other: &Self) -> bool {
147 <[u8; 32]>::from(self.0)
148 .ct_eq(&<[u8; 32]>::from(other.0))
149 .into()
150 }
151}
152
153impl Eq for SpendValidatingKey {}
154
155impl SpendValidatingKey {
156 #[cfg(all(feature = "circuit", test))]
158 pub(crate) fn fake_random<R: RngCore>(mut rng: R) -> Self {
159 loop {
160 if let Some(k) = Self::from_bytes(&jubjub::SubgroupPoint::random(&mut rng).to_bytes()) {
161 break k;
162 }
163 }
164 }
165
166 #[cfg(feature = "temporary-zcashd")]
168 pub fn temporary_zcash_from_bytes(bytes: &[u8]) -> Option<Self> {
169 Self::from_bytes(bytes)
170 }
171
172 pub(crate) fn from_bytes(bytes: &[u8]) -> Option<Self> {
174 <[u8; 32]>::try_from(bytes)
175 .ok()
176 .and_then(|b| {
177 jubjub::SubgroupPoint::from_bytes(&b)
183 .and_then(|p| {
184 CtOption::new(
185 redjubjub::VerificationKey::try_from(b)
186 .expect("RedJubjub permits the set of valid SpendValidatingKeys"),
187 !p.is_identity(),
188 )
189 })
190 .into()
191 })
192 .map(SpendValidatingKey)
193 }
194
195 pub fn to_bytes(&self) -> [u8; 32] {
198 <[u8; 32]>::from(self.0)
199 }
200
201 pub fn randomize(&self, randomizer: &jubjub::Scalar) -> redjubjub::VerificationKey<SpendAuth> {
203 self.0.randomize(randomizer)
204 }
205}
206
207#[derive(Clone, Copy, Debug, PartialEq, Eq)]
209pub struct OutgoingViewingKey(pub [u8; 32]);
210
211#[derive(Clone)]
213pub struct ExpandedSpendingKey {
214 pub ask: SpendAuthorizingKey,
215 pub nsk: jubjub::Fr,
216 pub ovk: OutgoingViewingKey,
217}
218
219impl fmt::Debug for ExpandedSpendingKey {
220 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221 f.debug_struct("ExpandedSpendingKey")
222 .finish_non_exhaustive()
223 }
224}
225
226impl ExpandedSpendingKey {
227 pub fn from_spending_key(sk: &[u8]) -> Self {
234 let ask =
235 SpendAuthorizingKey::from_spending_key(sk).expect("negligible chance of ask == 0");
236 let nsk = jubjub::Fr::from_bytes_wide(&PrfExpand::SAPLING_NSK.with(sk));
237 let mut ovk = OutgoingViewingKey([0u8; 32]);
238 ovk.0
239 .copy_from_slice(&PrfExpand::SAPLING_OVK.with(sk)[..32]);
240 ExpandedSpendingKey { ask, nsk, ovk }
241 }
242
243 pub fn proof_generation_key(&self) -> ProofGenerationKey {
244 ProofGenerationKey {
245 ak: (&self.ask).into(),
246 nsk: self.nsk,
247 }
248 }
249
250 pub fn from_bytes(b: &[u8]) -> Result<Self, DecodingError> {
254 if b.len() != 96 {
255 return Err(DecodingError::LengthInvalid {
256 expected: 96,
257 actual: b.len(),
258 });
259 }
260
261 let ask = SpendAuthorizingKey::from_bytes(&b[0..32]).ok_or(DecodingError::InvalidAsk)?;
262 let nsk = Option::from(jubjub::Fr::from_repr(b[32..64].try_into().unwrap()))
263 .ok_or(DecodingError::InvalidNsk)?;
264 let ovk = OutgoingViewingKey(b[64..96].try_into().unwrap());
265
266 Ok(ExpandedSpendingKey { ask, nsk, ovk })
267 }
268
269 pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
270 let mut repr = [0u8; 96];
271 reader.read_exact(repr.as_mut())?;
272 Self::from_bytes(&repr).map_err(|e| match e {
273 DecodingError::InvalidAsk => {
274 io::Error::new(io::ErrorKind::InvalidData, "ask not in field")
275 }
276 DecodingError::InvalidNsk => {
277 io::Error::new(io::ErrorKind::InvalidData, "nsk not in field")
278 }
279 DecodingError::LengthInvalid { .. } | DecodingError::UnsupportedChildIndex => {
280 unreachable!()
281 }
282 })
283 }
284
285 pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
286 writer.write_all(&self.to_bytes())
287 }
288
289 pub fn to_bytes(&self) -> [u8; 96] {
293 let mut result = [0u8; 96];
294 result[0..32].copy_from_slice(&self.ask.to_bytes());
295 result[32..64].copy_from_slice(&self.nsk.to_repr());
296 result[64..96].copy_from_slice(&self.ovk.0);
297 result
298 }
299}
300
301#[derive(Clone)]
302pub struct ProofGenerationKey {
303 pub ak: SpendValidatingKey,
304 pub nsk: jubjub::Fr,
305}
306
307impl fmt::Debug for ProofGenerationKey {
308 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
309 f.debug_struct("ProofGenerationKey")
310 .field("ak", &self.ak)
311 .finish_non_exhaustive()
312 }
313}
314
315impl ProofGenerationKey {
316 pub fn to_viewing_key(&self) -> ViewingKey {
317 ViewingKey {
318 ak: self.ak.clone(),
319 nk: NullifierDerivingKey(constants::PROOF_GENERATION_KEY_GENERATOR * self.nsk),
320 }
321 }
322}
323
324#[derive(Debug, Copy, Clone, PartialEq, Eq)]
326pub struct NullifierDerivingKey(pub jubjub::SubgroupPoint);
327
328#[derive(Debug, Clone)]
329pub struct ViewingKey {
330 pub ak: SpendValidatingKey,
331 pub nk: NullifierDerivingKey,
332}
333
334impl ViewingKey {
335 pub fn rk(&self, ar: jubjub::Fr) -> redjubjub::VerificationKey<SpendAuth> {
336 self.ak.randomize(&ar)
337 }
338
339 pub fn ivk(&self) -> SaplingIvk {
340 SaplingIvk(crh_ivk(self.ak.to_bytes(), self.nk.0.to_bytes()))
341 }
342
343 pub fn to_payment_address(&self, diversifier: Diversifier) -> Option<PaymentAddress> {
344 self.ivk().to_payment_address(diversifier)
345 }
346}
347
348#[derive(Debug)]
350pub struct FullViewingKey {
351 pub vk: ViewingKey,
352 pub ovk: OutgoingViewingKey,
353}
354
355impl Clone for FullViewingKey {
356 fn clone(&self) -> Self {
357 FullViewingKey {
358 vk: ViewingKey {
359 ak: self.vk.ak.clone(),
360 nk: self.vk.nk,
361 },
362 ovk: self.ovk,
363 }
364 }
365}
366
367impl FullViewingKey {
368 pub fn from_expanded_spending_key(expsk: &ExpandedSpendingKey) -> Self {
369 FullViewingKey {
370 vk: ViewingKey {
371 ak: (&expsk.ask).into(),
372 nk: NullifierDerivingKey(PROOF_GENERATION_KEY_GENERATOR * expsk.nsk),
373 },
374 ovk: expsk.ovk,
375 }
376 }
377
378 pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
379 let ak = {
380 let mut buf = [0u8; 32];
381 reader.read_exact(&mut buf)?;
382 SpendValidatingKey::from_bytes(&buf)
383 };
384 let nk = {
385 let mut buf = [0u8; 32];
386 reader.read_exact(&mut buf)?;
387 jubjub::SubgroupPoint::from_bytes(&buf)
388 };
389 if ak.is_none() {
390 return Err(io::Error::new(
391 io::ErrorKind::InvalidInput,
392 "ak not of prime order",
393 ));
394 }
395 if nk.is_none().into() {
396 return Err(io::Error::new(
397 io::ErrorKind::InvalidInput,
398 "nk not in prime-order subgroup",
399 ));
400 }
401 let ak = ak.unwrap();
402 let nk = NullifierDerivingKey(nk.unwrap());
403
404 let mut ovk = [0u8; 32];
405 reader.read_exact(&mut ovk)?;
406
407 Ok(FullViewingKey {
408 vk: ViewingKey { ak, nk },
409 ovk: OutgoingViewingKey(ovk),
410 })
411 }
412
413 pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
414 writer.write_all(&self.vk.ak.to_bytes())?;
415 writer.write_all(&self.vk.nk.0.to_bytes())?;
416 writer.write_all(&self.ovk.0)?;
417
418 Ok(())
419 }
420
421 pub fn to_bytes(&self) -> [u8; 96] {
422 let mut result = [0u8; 96];
423 self.write(&mut result[..])
424 .expect("should be able to serialize a FullViewingKey");
425 result
426 }
427}
428
429#[derive(Debug, Clone)]
430pub struct SaplingIvk(pub jubjub::Fr);
431
432impl SaplingIvk {
433 pub fn to_payment_address(&self, diversifier: Diversifier) -> Option<PaymentAddress> {
434 let prepared_ivk = PreparedIncomingViewingKey::new(self);
435 DiversifiedTransmissionKey::derive(&prepared_ivk, &diversifier)
436 .and_then(|pk_d| PaymentAddress::from_parts(diversifier, pk_d))
437 }
438
439 pub fn to_repr(&self) -> [u8; 32] {
440 self.0.to_repr()
441 }
442}
443
444#[derive(Clone, Debug)]
446pub struct PreparedIncomingViewingKey(PreparedScalar);
447
448#[cfg(feature = "std")]
449impl memuse::DynamicUsage for PreparedIncomingViewingKey {
450 fn dynamic_usage(&self) -> usize {
451 self.0.dynamic_usage()
452 }
453
454 fn dynamic_usage_bounds(&self) -> (usize, Option<usize>) {
455 self.0.dynamic_usage_bounds()
456 }
457}
458
459impl PreparedIncomingViewingKey {
460 pub fn new(ivk: &SaplingIvk) -> Self {
462 Self(PreparedScalar::new(&ivk.0))
463 }
464}
465
466#[derive(Copy, Clone, Debug, PartialEq, Eq)]
467pub struct Diversifier(pub [u8; 11]);
468
469impl Diversifier {
470 pub fn g_d(&self) -> Option<jubjub::SubgroupPoint> {
471 diversify_hash(&self.0)
472 }
473}
474
475#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
484pub struct DiversifiedTransmissionKey(jubjub::SubgroupPoint);
485
486impl DiversifiedTransmissionKey {
487 pub(crate) fn derive(ivk: &PreparedIncomingViewingKey, d: &Diversifier) -> Option<Self> {
493 d.g_d()
494 .map(PreparedBaseSubgroup::new)
495 .map(|g_d| ka_sapling_derive_public_subgroup_prepared(&ivk.0, &g_d))
496 .map(DiversifiedTransmissionKey)
497 }
498
499 pub(crate) fn from_bytes(bytes: &[u8; 32]) -> CtOption<Self> {
501 jubjub::SubgroupPoint::from_bytes(bytes).map(DiversifiedTransmissionKey)
502 }
503
504 pub(crate) fn to_bytes(self) -> [u8; 32] {
506 self.0.to_bytes()
507 }
508
509 pub(crate) fn is_identity(&self) -> bool {
511 self.0.is_identity().into()
512 }
513
514 pub fn inner(&self) -> jubjub::SubgroupPoint {
519 self.0
520 }
521}
522
523impl ConditionallySelectable for DiversifiedTransmissionKey {
524 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
525 DiversifiedTransmissionKey(jubjub::SubgroupPoint::conditional_select(
526 &a.0, &b.0, choice,
527 ))
528 }
529}
530
531#[derive(Debug)]
542pub struct EphemeralSecretKey(pub(crate) jubjub::Scalar);
543
544impl ConstantTimeEq for EphemeralSecretKey {
545 fn ct_eq(&self, other: &Self) -> subtle::Choice {
546 self.0.ct_eq(&other.0)
547 }
548}
549
550impl EphemeralSecretKey {
551 pub(crate) fn from_bytes(bytes: &[u8; 32]) -> CtOption<Self> {
552 jubjub::Scalar::from_bytes(bytes).map(EphemeralSecretKey)
553 }
554
555 pub(crate) fn derive_public(&self, g_d: jubjub::ExtendedPoint) -> EphemeralPublicKey {
556 EphemeralPublicKey(ka_sapling_derive_public(&self.0, &g_d))
557 }
558
559 pub(crate) fn agree(&self, pk_d: &DiversifiedTransmissionKey) -> SharedSecret {
560 SharedSecret(ka_sapling_agree(&self.0, &pk_d.0.into()))
561 }
562}
563
564#[derive(Debug)]
575pub struct EphemeralPublicKey(jubjub::ExtendedPoint);
576
577impl EphemeralPublicKey {
578 pub(crate) fn from_affine(epk: jubjub::AffinePoint) -> Self {
579 EphemeralPublicKey(epk.into())
580 }
581
582 pub(crate) fn from_bytes(bytes: &[u8; 32]) -> CtOption<Self> {
583 jubjub::ExtendedPoint::from_bytes(bytes).map(EphemeralPublicKey)
584 }
585
586 pub(crate) fn to_bytes(&self) -> EphemeralKeyBytes {
587 EphemeralKeyBytes(self.0.to_bytes())
588 }
589}
590
591#[derive(Clone, Debug)]
593pub struct PreparedEphemeralPublicKey(PreparedBase);
594
595impl PreparedEphemeralPublicKey {
596 pub(crate) fn new(epk: EphemeralPublicKey) -> Self {
597 PreparedEphemeralPublicKey(PreparedBase::new(epk.0))
598 }
599
600 pub(crate) fn agree(&self, ivk: &PreparedIncomingViewingKey) -> SharedSecret {
601 SharedSecret(ka_sapling_agree_prepared(&ivk.0, &self.0))
602 }
603}
604
605#[derive(Debug)]
611pub struct SharedSecret(jubjub::SubgroupPoint);
612
613impl SharedSecret {
614 #[cfg(test)]
616 pub(crate) fn to_bytes(&self) -> [u8; 32] {
617 self.0.to_bytes()
618 }
619
620 pub(crate) fn batch_to_affine(
622 shared_secrets: Vec<Option<Self>>,
623 ) -> impl Iterator<Item = Option<jubjub::AffinePoint>> {
624 let secrets: Vec<_> = shared_secrets
626 .iter()
627 .filter_map(|s| s.as_ref().map(|s| jubjub::ExtendedPoint::from(s.0)))
628 .collect();
629
630 let mut secrets_affine = vec![jubjub::AffinePoint::identity(); secrets.len()];
632 group::Curve::batch_normalize(&secrets, &mut secrets_affine);
633
634 let mut secrets_affine = secrets_affine.into_iter();
636 shared_secrets
637 .into_iter()
638 .map(move |s| s.and_then(|_| secrets_affine.next()))
639 }
640
641 pub(crate) fn kdf_sapling(self, ephemeral_key: &EphemeralKeyBytes) -> Blake2bHash {
645 Self::kdf_sapling_inner(
646 jubjub::ExtendedPoint::from(self.0).to_affine(),
647 ephemeral_key,
648 )
649 }
650
651 pub(crate) fn kdf_sapling_inner(
653 secret: jubjub::AffinePoint,
654 ephemeral_key: &EphemeralKeyBytes,
655 ) -> Blake2bHash {
656 Blake2bParams::new()
657 .hash_length(32)
658 .personal(KDF_SAPLING_PERSONALIZATION)
659 .to_state()
660 .update(&secret.to_bytes())
661 .update(ephemeral_key.as_ref())
662 .finalize()
663 }
664}
665
666#[cfg(any(test, feature = "test-dependencies"))]
667#[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))]
668pub mod testing {
669 use proptest::collection::vec;
670 use proptest::prelude::*;
671
672 use super::{ExpandedSpendingKey, FullViewingKey, SaplingIvk};
673
674 prop_compose! {
675 pub fn arb_expanded_spending_key()(v in vec(any::<u8>(), 32..252)) -> ExpandedSpendingKey {
676 ExpandedSpendingKey::from_spending_key(&v)
677 }
678 }
679
680 prop_compose! {
681 pub fn arb_full_viewing_key()(sk in arb_expanded_spending_key()) -> FullViewingKey {
682 FullViewingKey::from_expanded_spending_key(&sk)
683 }
684 }
685
686 prop_compose! {
687 pub fn arb_incoming_viewing_key()(fvk in arb_full_viewing_key()) -> SaplingIvk {
688 fvk.vk.ivk()
689 }
690 }
691}
692
693#[cfg(test)]
694mod tests {
695 use alloc::string::ToString;
696 use group::{Group, GroupEncoding};
697
698 use super::{FullViewingKey, SpendAuthorizingKey, SpendValidatingKey};
699 use crate::{constants::SPENDING_KEY_GENERATOR, test_vectors};
700
701 #[test]
702 fn ak_must_be_prime_order() {
703 let mut buf = [0; 96];
704 let identity = jubjub::SubgroupPoint::identity();
705
706 buf[0..32].copy_from_slice(&identity.to_bytes());
708 buf[32..64].copy_from_slice(&identity.to_bytes());
709
710 assert_eq!(
712 FullViewingKey::read(&buf[..]).unwrap_err().to_string(),
713 "ak not of prime order"
714 );
715
716 let basepoint = SPENDING_KEY_GENERATOR;
718 buf[0..32].copy_from_slice(&basepoint.to_bytes());
719
720 assert!(FullViewingKey::read(&buf[..]).is_ok());
722 }
723
724 #[test]
725 fn spend_auth_sig_test_vectors() {
726 for tv in test_vectors::signatures::make_test_vectors() {
727 let sk = SpendAuthorizingKey::from_bytes(&tv.sk).unwrap();
728 let vk = SpendValidatingKey::from_bytes(&tv.vk).unwrap();
729 let rvk = redjubjub::VerificationKey::try_from(tv.rvk).unwrap();
730 let sig = redjubjub::Signature::from(tv.sig);
731 let rsig = redjubjub::Signature::from(tv.rsig);
732
733 let alpha = jubjub::Scalar::from_bytes(&tv.alpha).unwrap();
734
735 assert_eq!(<[u8; 32]>::from(sk.randomize(&alpha)), tv.rsk);
736 assert_eq!(vk.randomize(&alpha), rvk);
737
738 assert_eq!(
741 vk.0.verify(&tv.m, &rsig),
742 Err(redjubjub::Error::InvalidSignature),
743 );
744 assert_eq!(
745 rvk.verify(&tv.m, &sig),
746 Err(redjubjub::Error::InvalidSignature),
747 );
748 }
749 }
750}