1pub mod group_hash;
4pub mod keys;
5pub mod note_encryption;
6pub mod pedersen_hash;
7pub mod prover;
8pub mod redjubjub;
9pub mod util;
10
11use bitvec::{order::Lsb0, view::AsBits};
12use blake2s_simd::Params as Blake2sParams;
13use borsh::{BorshDeserialize, BorshSerialize};
14use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
15use ff::{Field, PrimeField};
16use group::{cofactor::CofactorGroup, Curve, Group, GroupEncoding};
17use incrementalmerkletree::{self, Altitude};
18use lazy_static::lazy_static;
19use rand_core::{CryptoRng, RngCore};
20use std::{
21 array::TryFromSliceError,
22 cmp::Ordering,
23 convert::TryFrom,
24 fmt::{Display, Formatter},
25 hash::{Hash, Hasher},
26 io::{self, Read, Write},
27 str::FromStr,
28};
29use subtle::{Choice, ConstantTimeEq, CtOption};
30
31use crate::{
32 asset_type::AssetType,
33 constants::{self, SPENDING_KEY_GENERATOR},
34 keys::prf_expand,
35 merkle_tree::{HashSer, Hashable},
36 transaction::components::amount::MAX_MONEY,
37};
38
39use self::{
40 group_hash::group_hash,
41 pedersen_hash::{pedersen_hash, Personalization},
42 redjubjub::{PrivateKey, PublicKey, Signature},
43};
44use borsh::schema::add_definition;
45use borsh::schema::Declaration;
46use borsh::schema::Definition;
47use borsh::schema::Fields;
48use borsh::BorshSchema;
49use std::collections::BTreeMap;
50
51pub const SAPLING_COMMITMENT_TREE_DEPTH: usize = 32;
52
53pub fn merkle_hash(depth: usize, lhs: &[u8; 32], rhs: &[u8; 32]) -> [u8; 32] {
55 let lhs = {
56 let mut tmp = [false; 256];
57 for (a, b) in tmp.iter_mut().zip(lhs.as_bits::<Lsb0>()) {
58 *a = *b;
59 }
60 tmp
61 };
62
63 let rhs = {
64 let mut tmp = [false; 256];
65 for (a, b) in tmp.iter_mut().zip(rhs.as_bits::<Lsb0>()) {
66 *a = *b;
67 }
68 tmp
69 };
70
71 jubjub::ExtendedPoint::from(pedersen_hash(
72 Personalization::MerkleTree(depth),
73 lhs.iter()
74 .copied()
75 .take(bls12_381::Scalar::NUM_BITS as usize)
76 .chain(
77 rhs.iter()
78 .copied()
79 .take(bls12_381::Scalar::NUM_BITS as usize),
80 ),
81 ))
82 .to_affine()
83 .get_u()
84 .to_repr()
85}
86
87#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
89#[derive(Clone, Copy, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize, Default)]
90pub struct Node {
91 repr: [u8; 32],
92}
93
94impl Node {
95 pub fn new(repr: [u8; 32]) -> Self {
96 Node { repr }
97 }
98
99 pub fn from_scalar(cmu: bls12_381::Scalar) -> Self {
101 Self {
102 repr: cmu.to_repr(),
103 }
104 }
105}
106
107impl incrementalmerkletree::Hashable for Node {
108 fn empty_leaf() -> Self {
109 Node {
110 repr: Note::uncommitted().to_repr(),
111 }
112 }
113
114 fn combine(altitude: Altitude, lhs: &Self, rhs: &Self) -> Self {
115 Node {
116 repr: merkle_hash(altitude.into(), &lhs.repr, &rhs.repr),
117 }
118 }
119
120 fn empty_root(altitude: Altitude) -> Self {
121 EMPTY_ROOTS[<usize>::from(altitude)]
122 }
123}
124
125impl HashSer for Node {
126 fn read<R: Read>(mut reader: R) -> io::Result<Self> {
127 let mut repr = [0u8; 32];
128 reader.read_exact(&mut repr)?;
129 Ok(Node { repr })
130 }
131
132 fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
133 writer.write_all(self.repr.as_ref())
134 }
135}
136
137impl From<Node> for bls12_381::Scalar {
138 fn from(node: Node) -> Self {
139 bls12_381::Scalar::from_repr(node.repr).unwrap()
141 }
142}
143
144lazy_static! {
145 static ref EMPTY_ROOTS: Vec<Node> = {
146 let mut v = vec![Node::blank()];
147 for d in 0..SAPLING_COMMITMENT_TREE_DEPTH {
148 let next = Node::combine(d, &v[d], &v[d]);
149 v.push(next);
150 }
151 v
152 };
153}
154
155pub fn spend_sig<R: RngCore + CryptoRng>(
157 ask: PrivateKey,
158 ar: jubjub::Fr,
159 sighash: &[u8; 32],
160 rng: &mut R,
161) -> Signature {
162 spend_sig_internal(ask, ar, sighash, rng)
163}
164
165pub(crate) fn spend_sig_internal<R: RngCore>(
166 ask: PrivateKey,
167 ar: jubjub::Fr,
168 sighash: &[u8; 32],
169 rng: &mut R,
170) -> Signature {
171 let rsk = ask.randomize(ar);
173
174 let rk = PublicKey::from_private(&rsk, SPENDING_KEY_GENERATOR);
176
177 let mut data_to_be_signed = [0u8; 64];
179 data_to_be_signed[0..32].copy_from_slice(&rk.0.to_bytes());
180 data_to_be_signed[32..64].copy_from_slice(&sighash[..]);
181
182 rsk.sign(&data_to_be_signed, rng, SPENDING_KEY_GENERATOR)
184}
185
186#[derive(Clone)]
187pub struct ValueCommitment {
188 pub asset_generator: jubjub::ExtendedPoint,
189 pub value: u64,
190 pub randomness: jubjub::Fr,
191}
192
193impl ValueCommitment {
194 pub fn commitment(&self) -> jubjub::SubgroupPoint {
195 (CofactorGroup::clear_cofactor(&self.asset_generator) * jubjub::Fr::from(self.value))
196 + (constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR * self.randomness)
197 }
198}
199
200#[derive(Clone, Debug)]
201pub struct ProofGenerationKey {
202 pub ak: jubjub::SubgroupPoint,
203 pub nsk: jubjub::Fr,
204}
205
206impl ProofGenerationKey {
207 pub fn to_viewing_key(&self) -> ViewingKey {
208 ViewingKey {
209 ak: self.ak,
210 nk: NullifierDerivingKey(constants::PROOF_GENERATION_KEY_GENERATOR * self.nsk),
211 }
212 }
213}
214
215impl BorshSerialize for ProofGenerationKey {
216 fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
217 writer.write_all(&self.ak.to_bytes())?;
218 writer.write_all(&self.nsk.to_repr())?;
219 Ok(())
220 }
221}
222
223impl BorshDeserialize for ProofGenerationKey {
224 fn deserialize_reader<R: Read>(reader: &mut R) -> io::Result<Self> {
225 let ak = {
226 let mut buf = [0u8; 32];
227 reader.read_exact(&mut buf)?;
228 jubjub::SubgroupPoint::from_bytes(&buf)
229 };
230 if ak.is_none().into() {
231 return Err(io::Error::new(
232 io::ErrorKind::InvalidInput,
233 "ak not in prime-order subgroup",
234 ));
235 }
236 let nsk_bytes = <[u8; 32]>::deserialize_reader(reader)?;
237 let nsk = Option::from(jubjub::Fr::from_bytes(&nsk_bytes))
238 .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "nsk not in field"))?;
239 Ok(Self {
240 ak: ak.unwrap(),
241 nsk,
242 })
243 }
244}
245
246impl BorshSchema for ProofGenerationKey {
247 fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
248 let definition = Definition::Struct {
249 fields: Fields::NamedFields(vec![
250 ("ak".into(), <[u8; 32]>::declaration()),
251 ("nsk".into(), <[u8; 32]>::declaration()),
252 ]),
253 };
254 add_definition(Self::declaration(), definition, definitions);
255 <[u8; 32]>::add_definitions_recursively(definitions);
256 }
257
258 fn declaration() -> Declaration {
259 "ProofGenerationKey".into()
260 }
261}
262
263#[derive(Debug, Copy, Clone, PartialEq, Eq)]
265#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
266pub struct NullifierDerivingKey(pub jubjub::SubgroupPoint);
267
268impl BorshSerialize for NullifierDerivingKey {
269 fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
270 writer.write_all(&self.0.to_bytes())
271 }
272}
273
274impl BorshDeserialize for NullifierDerivingKey {
275 fn deserialize_reader<R: Read>(reader: &mut R) -> io::Result<Self> {
276 let nk = {
277 let mut buf = [0u8; 32];
278 reader.read_exact(&mut buf)?;
279 jubjub::SubgroupPoint::from_bytes(&buf)
280 };
281 if nk.is_none().into() {
282 return Err(io::Error::new(
283 io::ErrorKind::InvalidInput,
284 "nk not in prime-order subgroup",
285 ));
286 }
287 Ok(Self(nk.unwrap()))
288 }
289}
290
291impl BorshSchema for NullifierDerivingKey {
292 fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
293 let definition = Definition::Struct {
294 fields: Fields::UnnamedFields(vec![<[u8; 32]>::declaration()]),
295 };
296 add_definition(Self::declaration(), definition, definitions);
297 <[u8; 32]>::add_definitions_recursively(definitions);
298 }
299
300 fn declaration() -> Declaration {
301 "NullifierDerivingKey".into()
302 }
303}
304
305#[derive(Debug, PartialEq, Eq, Clone, Copy)]
306#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
307pub struct ViewingKey {
308 pub ak: jubjub::SubgroupPoint,
309 pub nk: NullifierDerivingKey,
310}
311
312impl Hash for ViewingKey {
313 fn hash<H>(&self, state: &mut H)
314 where
315 H: Hasher,
316 {
317 self.ak.to_bytes().hash(state);
318 self.nk.0.to_bytes().hash(state);
319 }
320}
321
322impl ViewingKey {
323 pub fn rk(&self, ar: jubjub::Fr) -> jubjub::SubgroupPoint {
324 self.ak + constants::SPENDING_KEY_GENERATOR * ar
325 }
326
327 pub fn ivk(&self) -> SaplingIvk {
328 let mut h = [0; 32];
329 h.copy_from_slice(
330 Blake2sParams::new()
331 .hash_length(32)
332 .personal(constants::CRH_IVK_PERSONALIZATION)
333 .to_state()
334 .update(&self.ak.to_bytes())
335 .update(&self.nk.0.to_bytes())
336 .finalize()
337 .as_bytes(),
338 );
339
340 h[31] &= 0b0000_0111;
342
343 SaplingIvk(jubjub::Fr::from_repr(h).unwrap())
344 }
345
346 pub fn to_payment_address(&self, diversifier: Diversifier) -> Option<PaymentAddress> {
347 self.ivk().to_payment_address(diversifier)
348 }
349
350 pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
351 let ak = {
352 let mut buf = [0u8; 32];
353 reader.read_exact(&mut buf)?;
354 jubjub::SubgroupPoint::from_bytes(&buf).and_then(|p| CtOption::new(p, !p.is_identity()))
355 };
356 let nk = {
357 let mut buf = [0u8; 32];
358 reader.read_exact(&mut buf)?;
359 jubjub::SubgroupPoint::from_bytes(&buf)
360 };
361 if ak.is_none().into() {
362 return Err(io::Error::new(
363 io::ErrorKind::InvalidInput,
364 "ak not of prime order",
365 ));
366 }
367 if nk.is_none().into() {
368 return Err(io::Error::new(
369 io::ErrorKind::InvalidInput,
370 "nk not in prime-order subgroup",
371 ));
372 }
373 let ak = ak.unwrap();
374 let nk = nk.unwrap();
375
376 Ok(ViewingKey {
377 ak,
378 nk: NullifierDerivingKey(nk),
379 })
380 }
381
382 pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
383 writer.write_all(&self.ak.to_bytes())?;
384 writer.write_all(&self.nk.0.to_bytes())?;
385
386 Ok(())
387 }
388
389 pub fn to_bytes(&self) -> [u8; 64] {
390 let mut result = [0u8; 64];
391 self.write(&mut result[..])
392 .expect("should be able to serialize a ViewingKey");
393 result
394 }
395}
396
397impl BorshSerialize for ViewingKey {
398 fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
399 self.write(writer)
400 }
401}
402
403impl BorshDeserialize for ViewingKey {
404 fn deserialize_reader<R: Read>(reader: &mut R) -> io::Result<Self> {
405 Self::read(reader)
406 }
407}
408
409impl BorshSchema for ViewingKey {
410 fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
411 let definition = Definition::Struct {
412 fields: Fields::NamedFields(vec![
413 ("ak".into(), <[u8; 32]>::declaration()),
414 ("nk".into(), NullifierDerivingKey::declaration()),
415 ]),
416 };
417 add_definition(Self::declaration(), definition, definitions);
418 <[u8; 32]>::add_definitions_recursively(definitions);
419 NullifierDerivingKey::add_definitions_recursively(definitions);
420 }
421
422 fn declaration() -> Declaration {
423 "ViewingKey".into()
424 }
425}
426
427impl PartialOrd for ViewingKey {
428 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
429 Some(self.cmp(other))
430 }
431}
432
433impl Ord for ViewingKey {
434 fn cmp(&self, other: &Self) -> Ordering {
435 self.to_bytes().cmp(&other.to_bytes())
436 }
437}
438
439#[derive(Debug, Clone)]
440pub struct SaplingIvk(pub jubjub::Fr);
441
442impl SaplingIvk {
443 pub fn to_payment_address(&self, diversifier: Diversifier) -> Option<PaymentAddress> {
444 diversifier.g_d().and_then(|g_d| {
445 let pk_d = g_d * self.0;
446
447 PaymentAddress::from_parts(diversifier, pk_d)
448 })
449 }
450
451 pub fn to_repr(&self) -> [u8; 32] {
452 self.0.to_repr()
453 }
454}
455
456#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
457#[derive(
458 Copy, Clone, Debug, PartialEq, Eq, Hash, BorshSerialize, BorshDeserialize, BorshSchema,
459)]
460pub struct Diversifier(pub [u8; 11]);
461
462impl Diversifier {
463 pub fn g_d(&self) -> Option<jubjub::SubgroupPoint> {
464 group_hash(&self.0, constants::KEY_DIVERSIFICATION_PERSONALIZATION)
465 }
466}
467
468#[derive(Clone, Copy, Debug)]
475pub struct PaymentAddress {
476 pk_d: jubjub::SubgroupPoint,
477 diversifier: Diversifier,
478}
479
480impl PartialEq for PaymentAddress {
481 fn eq(&self, other: &Self) -> bool {
482 self.pk_d == other.pk_d && self.diversifier == other.diversifier
483 }
484}
485
486impl Eq for PaymentAddress {}
487
488impl PaymentAddress {
489 pub fn from_parts(diversifier: Diversifier, pk_d: jubjub::SubgroupPoint) -> Option<Self> {
493 if pk_d.is_identity().into() {
494 None
495 } else {
496 Some(PaymentAddress { pk_d, diversifier })
497 }
498 }
499
500 #[cfg(test)]
504 #[allow(dead_code)]
505 pub(crate) fn from_parts_unchecked(
506 diversifier: Diversifier,
507 pk_d: jubjub::SubgroupPoint,
508 ) -> Self {
509 PaymentAddress { pk_d, diversifier }
510 }
511
512 pub fn from_bytes(bytes: &[u8; 43]) -> Option<Self> {
514 let diversifier = {
515 let mut tmp = [0; 11];
516 tmp.copy_from_slice(&bytes[0..11]);
517 Diversifier(tmp)
518 };
519 diversifier.g_d()?;
521
522 let pk_d = jubjub::SubgroupPoint::from_bytes(bytes[11..43].try_into().unwrap());
523 if pk_d.is_some().into() {
524 PaymentAddress::from_parts(diversifier, pk_d.unwrap())
525 } else {
526 None
527 }
528 }
529
530 pub fn to_bytes(&self) -> [u8; 43] {
532 let mut bytes = [0; 43];
533 bytes[0..11].copy_from_slice(&self.diversifier.0);
534 bytes[11..].copy_from_slice(&self.pk_d.to_bytes());
535 bytes
536 }
537
538 pub fn diversifier(&self) -> &Diversifier {
540 &self.diversifier
541 }
542
543 pub fn pk_d(&self) -> &jubjub::SubgroupPoint {
545 &self.pk_d
546 }
547
548 pub fn g_d(&self) -> Option<jubjub::SubgroupPoint> {
549 self.diversifier.g_d()
550 }
551
552 pub fn create_note(&self, asset_type: AssetType, value: u64, rseed: Rseed) -> Option<Note> {
553 self.g_d().map(|g_d| Note {
554 asset_type,
555 value,
556 rseed,
557 g_d,
558 pk_d: self.pk_d,
559 })
560 }
561}
562
563impl Display for PaymentAddress {
564 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
565 write!(f, "{}", hex::encode(self.to_bytes()))
566 }
567}
568
569impl FromStr for PaymentAddress {
570 type Err = io::Error;
571
572 fn from_str(s: &str) -> Result<Self, Self::Err> {
573 let vec = hex::decode(s).map_err(|x| io::Error::new(io::ErrorKind::InvalidData, x))?;
574 BorshDeserialize::try_from_slice(&vec)
575 }
576}
577
578impl PartialOrd for PaymentAddress {
579 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
580 Some(self.cmp(other))
581 }
582}
583impl Ord for PaymentAddress {
584 fn cmp(&self, other: &Self) -> Ordering {
585 self.to_bytes().cmp(&other.to_bytes())
586 }
587}
588impl Hash for PaymentAddress {
589 fn hash<H: Hasher>(&self, state: &mut H) {
590 self.to_bytes().hash(state)
591 }
592}
593
594impl BorshSerialize for PaymentAddress {
595 fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
596 writer.write(self.to_bytes().as_ref()).and(Ok(()))
597 }
598}
599impl BorshDeserialize for PaymentAddress {
600 fn deserialize_reader<R: Read>(reader: &mut R) -> io::Result<Self> {
601 let mut data = [0u8; 43];
602 reader.read_exact(&mut data)?;
603 let res = Self::from_bytes(&data);
604 let pa = res.ok_or_else(|| io::Error::from(io::ErrorKind::InvalidData))?;
605 Ok(pa)
606 }
607}
608impl BorshSchema for PaymentAddress {
609 fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
610 let definition = Definition::Struct {
611 fields: Fields::NamedFields(vec![
612 ("diversifier".into(), Diversifier::declaration()),
613 ("pk_d".into(), <[u8; 32]>::declaration()),
614 ]),
615 };
616 add_definition(Self::declaration(), definition, definitions);
617 Diversifier::add_definitions_recursively(definitions);
618 <[u8; 32]>::add_definitions_recursively(definitions);
619 }
620
621 fn declaration() -> Declaration {
622 "PaymentAddress".into()
623 }
624}
625
626#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
632#[derive(Copy, Clone, Debug)]
633pub enum Rseed {
634 BeforeZip212(jubjub::Fr),
635 AfterZip212([u8; 32]),
636}
637
638impl BorshSchema for Rseed {
639 fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
640 let definition = Definition::Enum {
641 tag_width: 1,
642 variants: vec![
643 (1, "BeforeZip212".into(), <[u8; 32]>::declaration()),
644 (2, "AfterZip212".into(), <[u8; 32]>::declaration()),
645 ],
646 };
647 add_definition(Self::declaration(), definition, definitions);
648 <[u8; 32]>::add_definitions_recursively(definitions);
649 }
650
651 fn declaration() -> Declaration {
652 "Rseed".into()
653 }
654}
655
656impl BorshSerialize for Rseed {
657 fn serialize<W: std::io::Write>(&self, writer: &mut W) -> io::Result<()> {
658 match self {
659 Rseed::BeforeZip212(rcm) => {
660 writer.write_u8(1)?;
662 writer.write_all(&rcm.to_repr())
664 }
665 Rseed::AfterZip212(rseed) => {
666 writer.write_u8(2)?;
668 writer.write_all(rseed)
670 }
671 }?;
672 Ok(())
673 }
674}
675
676impl BorshDeserialize for Rseed {
677 fn deserialize_reader<R: Read>(reader: &mut R) -> io::Result<Self> {
678 let rseed_type = reader.read_u8()?;
680 let rseed_bytes = <[u8; 32]>::deserialize_reader(reader)?;
682 let rseed = if rseed_type == 0x01 {
683 let data = Option::from(jubjub::Fr::from_bytes(&rseed_bytes))
684 .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "rseed not in field"))?;
685 Rseed::BeforeZip212(data)
686 } else {
687 Rseed::AfterZip212(rseed_bytes)
688 };
689 Ok(rseed)
690 }
691}
692
693#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
695#[derive(
696 Copy,
697 Clone,
698 Debug,
699 PartialEq,
700 Eq,
701 PartialOrd,
702 Ord,
703 Hash,
704 BorshSerialize,
705 BorshDeserialize,
706 BorshSchema,
707)]
708pub struct Nullifier(pub [u8; 32]);
709
710impl Nullifier {
711 pub fn from_slice(bytes: &[u8]) -> Result<Nullifier, TryFromSliceError> {
712 bytes.try_into().map(Nullifier)
713 }
714
715 pub fn to_vec(&self) -> Vec<u8> {
716 self.0.to_vec()
717 }
718}
719impl AsRef<[u8]> for Nullifier {
720 fn as_ref(&self) -> &[u8] {
721 &self.0
722 }
723}
724
725impl ConstantTimeEq for Nullifier {
726 fn ct_eq(&self, other: &Self) -> Choice {
727 self.0.ct_eq(&other.0)
728 }
729}
730
731#[derive(Clone, Copy, Debug, PartialEq, Eq)]
732pub struct NoteValue(u64);
733
734impl TryFrom<u64> for NoteValue {
735 type Error = ();
736
737 fn try_from(value: u64) -> Result<Self, Self::Error> {
738 if value <= MAX_MONEY {
739 Ok(NoteValue(value))
740 } else {
741 Err(())
742 }
743 }
744}
745
746impl From<NoteValue> for u64 {
747 fn from(value: NoteValue) -> u64 {
748 value.0
749 }
750}
751
752#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
753#[derive(Clone, Debug, Copy)]
754pub struct Note<R = Rseed> {
755 pub asset_type: AssetType,
757 pub value: u64,
759 pub g_d: jubjub::SubgroupPoint,
761 pub pk_d: jubjub::SubgroupPoint,
763 pub rseed: R,
765}
766
767impl PartialEq for Note {
768 fn eq(&self, other: &Self) -> bool {
769 self.value == other.value
770 && self.asset_type == other.asset_type
771 && self.g_d == other.g_d
772 && self.pk_d == other.pk_d
773 && self.rcm() == other.rcm()
774 }
775}
776
777impl Note {
778 pub fn uncommitted() -> bls12_381::Scalar {
779 bls12_381::Scalar::one()
782 }
783
784 fn cm_full_point(&self) -> jubjub::SubgroupPoint {
786 let mut note_contents = vec![];
788
789 note_contents.extend_from_slice(&self.asset_type.asset_generator().to_bytes());
791
792 note_contents.write_u64::<LittleEndian>(self.value).unwrap();
794
795 note_contents.extend_from_slice(&self.g_d.to_bytes());
797
798 note_contents.extend_from_slice(&self.pk_d.to_bytes());
800
801 assert_eq!(note_contents.len(), 32 + 32 + 32 + 8);
802
803 let hash_of_contents = pedersen_hash(
805 Personalization::NoteCommitment,
806 note_contents
807 .into_iter()
808 .flat_map(|byte| (0..8).map(move |i| ((byte >> i) & 1) == 1)),
809 );
810
811 (constants::NOTE_COMMITMENT_RANDOMNESS_GENERATOR * self.rcm()) + hash_of_contents
813 }
814
815 pub fn nf(&self, nk: &NullifierDerivingKey, position: u64) -> Nullifier {
818 let rho = self.cm_full_point()
820 + (constants::NULLIFIER_POSITION_GENERATOR * jubjub::Fr::from(position));
821
822 Nullifier::from_slice(
824 Blake2sParams::new()
825 .hash_length(32)
826 .personal(constants::PRF_NF_PERSONALIZATION)
827 .to_state()
828 .update(&nk.0.to_bytes())
829 .update(&rho.to_bytes())
830 .finalize()
831 .as_bytes(),
832 )
833 .unwrap()
834 }
835
836 pub fn cmu(&self) -> bls12_381::Scalar {
838 jubjub::ExtendedPoint::from(self.cm_full_point())
841 .to_affine()
842 .get_u()
843 }
844
845 pub fn rcm(&self) -> jubjub::Fr {
846 match self.rseed {
847 Rseed::BeforeZip212(rcm) => rcm,
848 Rseed::AfterZip212(rseed) => {
849 jubjub::Fr::from_bytes_wide(prf_expand(&rseed, &[0x04]).as_array())
850 }
851 }
852 }
853
854 pub fn generate_or_derive_esk<R: RngCore + CryptoRng>(&self, rng: &mut R) -> jubjub::Fr {
855 self.generate_or_derive_esk_internal(rng)
856 }
857
858 pub(crate) fn generate_or_derive_esk_internal<R: RngCore>(&self, rng: &mut R) -> jubjub::Fr {
859 match self.derive_esk() {
860 None => jubjub::Fr::random(rng),
861 Some(esk) => esk,
862 }
863 }
864
865 pub fn derive_esk(&self) -> Option<jubjub::Fr> {
867 match self.rseed {
868 Rseed::BeforeZip212(_) => None,
869 Rseed::AfterZip212(rseed) => Some(jubjub::Fr::from_bytes_wide(
870 prf_expand(&rseed, &[0x05]).as_array(),
871 )),
872 }
873 }
874
875 pub fn commitment(&self) -> Node {
878 Node {
879 repr: self.cmu().to_repr(),
880 }
881 }
882}
883
884impl<T: BorshSchema> BorshSchema for Note<T> {
885 fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
886 let definition = Definition::Struct {
887 fields: Fields::NamedFields(vec![
888 ("asset_type".into(), AssetType::declaration()),
889 ("value".into(), u64::declaration()),
890 ("g_d".into(), <[u8; 32]>::declaration()),
891 ("pk_d".into(), <[u8; 32]>::declaration()),
892 ("rseed".into(), T::declaration()),
893 ]),
894 };
895 add_definition(Self::declaration(), definition, definitions);
896 AssetType::add_definitions_recursively(definitions);
897 u64::add_definitions_recursively(definitions);
898 <[u8; 32]>::add_definitions_recursively(definitions);
899 T::add_definitions_recursively(definitions);
900 }
901
902 fn declaration() -> Declaration {
903 format!("Note<{}>", T::declaration())
904 }
905}
906
907impl<T: BorshSerialize> BorshSerialize for Note<T> {
908 fn serialize<W: std::io::Write>(&self, writer: &mut W) -> io::Result<()> {
909 self.asset_type.serialize(writer)?;
911 writer.write_u64::<LittleEndian>(self.value)?;
913 writer.write_all(&self.g_d.to_bytes())?;
915 writer.write_all(&self.pk_d.to_bytes())?;
917 self.rseed.serialize(writer)?;
919 Ok(())
920 }
921}
922
923impl<T: BorshDeserialize> BorshDeserialize for Note<T> {
924 fn deserialize_reader<R: Read>(reader: &mut R) -> io::Result<Self> {
925 let asset_type = AssetType::deserialize_reader(reader)?;
927 let value = reader.read_u64::<LittleEndian>()?;
929 let g_d_bytes = <[u8; 32]>::deserialize_reader(reader)?;
931 let g_d = Option::from(jubjub::SubgroupPoint::from_bytes(&g_d_bytes))
932 .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "g_d not in field"))?;
933 let pk_d_bytes = <[u8; 32]>::deserialize_reader(reader)?;
935 let pk_d = Option::from(jubjub::SubgroupPoint::from_bytes(&pk_d_bytes))
936 .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "pk_d not in field"))?;
937 let rseed = T::deserialize_reader(reader)?;
939 Ok(Note {
941 asset_type,
942 value,
943 g_d,
944 pk_d,
945 rseed,
946 })
947 }
948}
949#[cfg(any(test, feature = "test-dependencies"))]
950pub mod testing {
951 use proptest::prelude::*;
952 use std::cmp::min;
953
954 use crate::transaction::components::amount::MAX_MONEY;
955
956 use super::{
957 keys::testing::arb_full_viewing_key, Diversifier, Node, Note, NoteValue, PaymentAddress,
958 Rseed, SaplingIvk,
959 };
960
961 prop_compose! {
962 pub fn arb_note_value()(value in 0u64..=MAX_MONEY) -> NoteValue {
963 NoteValue::try_from(value).unwrap()
964 }
965 }
966
967 prop_compose! {
968 pub fn arb_positive_note_value(bound: u64)(
970 value in 1u64..=(min(bound, MAX_MONEY))
971 ) -> NoteValue {
972 NoteValue::try_from(value).unwrap()
973 }
974 }
975
976 prop_compose! {
977 pub fn arb_incoming_viewing_key()(fvk in arb_full_viewing_key()) -> SaplingIvk {
978 fvk.vk.ivk()
979 }
980 }
981
982 pub fn arb_payment_address() -> impl Strategy<Value = PaymentAddress> {
983 arb_incoming_viewing_key().prop_flat_map(|ivk: SaplingIvk| {
984 any::<[u8; 11]>().prop_filter_map(
985 "Sampled diversifier must generate a valid Sapling payment address.",
986 move |d| ivk.to_payment_address(Diversifier(d)),
987 )
988 })
989 }
990
991 prop_compose! {
992 pub fn arb_node()(value in prop::array::uniform32(prop::num::u8::ANY)) -> Node {
993 Node {
994 repr: value
995 }
996 }
997 }
998
999 prop_compose! {
1000 pub fn arb_note(value: NoteValue)(
1001 asset_type in crate::asset_type::testing::arb_asset_type(),
1002 addr in arb_payment_address(),
1003 rseed in prop::array::uniform32(prop::num::u8::ANY).prop_map(Rseed::AfterZip212)
1004 ) -> Note {
1005 Note {
1006 value: value.into(),
1007 g_d: addr.g_d().unwrap(), pk_d: *addr.pk_d(),
1009 rseed,
1010 asset_type
1011 }
1012 }
1013 }
1014}
1015
1016#[cfg(test)]
1017mod tests {
1018 use crate::{
1019 sapling::testing::{arb_note, arb_positive_note_value},
1020 sapling::Note,
1021 transaction::components::amount::MAX_MONEY,
1022 };
1023 use borsh::BorshDeserialize;
1024 use proptest::prelude::*;
1025
1026 proptest! {
1027 #![proptest_config(ProptestConfig::with_cases(10))]
1028 #[test]
1029 fn note_serialization(note in arb_positive_note_value(MAX_MONEY).prop_flat_map(arb_note)) {
1030 let borsh = borsh::to_vec(¬e).unwrap();
1032 let de_note: Note = BorshDeserialize::deserialize(&mut borsh.as_ref()).unwrap();
1034 prop_assert_eq!(note, de_note);
1035 }
1036 }
1037}