@@ -8,7 +8,7 @@ pub mod prover;
88pub mod redjubjub;
99pub mod util;
1010
11- use bitvec:: { order:: Lsb0 , view:: AsBits } ;
11+ use bitvec:: { array :: BitArray , order:: Lsb0 , view:: AsBits } ;
1212use blake2s_simd:: Params as Blake2sParams ;
1313use borsh:: { BorshDeserialize , BorshSerialize } ;
1414use byteorder:: { LittleEndian , ReadBytesExt , WriteBytesExt } ;
@@ -434,14 +434,8 @@ impl PaymentAddress {
434434 self . diversifier . g_d ( )
435435 }
436436
437- pub fn create_note ( & self , asset_type : AssetType , value : u64 , rseed : Rseed ) -> Option < Note > {
438- self . g_d ( ) . map ( |g_d| Note {
439- asset_type,
440- value,
441- rseed,
442- g_d,
443- pk_d : self . pk_d ,
444- } )
437+ pub fn create_note ( & self , asset_type : AssetType , value : u64 , rseed : Rseed ) -> Note {
438+ Note :: from_parts ( asset_type, * self , NoteValue :: from_raw ( value) , rseed)
445439 }
446440}
447441
@@ -531,9 +525,29 @@ impl ConstantTimeEq for Nullifier {
531525 }
532526}
533527
534- #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
528+ /// The non-negative value of an individual Sapling note.
529+ #[ derive( Clone , Copy , Debug , Default , PartialEq , Eq ) ]
535530pub struct NoteValue ( u64 ) ;
536531
532+ impl NoteValue {
533+ /// Returns the raw underlying value.
534+ pub fn inner ( & self ) -> u64 {
535+ self . 0
536+ }
537+
538+ /// Creates a note value from its raw numeric value.
539+ ///
540+ /// This only enforces that the value is an unsigned 64-bit integer. Callers should
541+ /// enforce any additional constraints on the value's valid range themselves.
542+ pub fn from_raw ( value : u64 ) -> Self {
543+ NoteValue ( value)
544+ }
545+
546+ pub ( crate ) fn to_le_bits ( self ) -> BitArray < [ u8 ; 8 ] , Lsb0 > {
547+ BitArray :: < _ , Lsb0 > :: new ( self . 0 . to_le_bytes ( ) )
548+ }
549+ }
550+
537551impl TryFrom < u64 > for NoteValue {
538552 type Error = ( ) ;
539553
@@ -552,36 +566,80 @@ impl From<NoteValue> for u64 {
552566 }
553567}
554568
569+ impl From < NoteValue > for i128 {
570+ fn from ( value : NoteValue ) -> i128 {
571+ value. 0 . into ( )
572+ }
573+ }
574+
575+ /// A discrete amount of funds received by an address.
555576#[ derive( Clone , Debug , Copy ) ]
556577pub struct Note {
557578 /// The asset type that the note represents
558579 pub asset_type : AssetType ,
580+ /// The recipient of the funds.
581+ recipient : PaymentAddress ,
559582 /// The value of the note
560- pub value : u64 ,
561- /// The diversified base of the address, GH(d)
562- pub g_d : jubjub:: SubgroupPoint ,
563- /// The public key of the address, g_d^ivk
564- pub pk_d : jubjub:: SubgroupPoint ,
565- /// rseed
583+ pub value : NoteValue ,
584+ /// The seed randomness for various note components.
566585 pub rseed : Rseed ,
567586}
568587
569588impl PartialEq for Note {
570589 fn eq ( & self , other : & Self ) -> bool {
571- self . value == other. value
572- && self . asset_type == other. asset_type
573- && self . g_d == other. g_d
574- && self . pk_d == other. pk_d
575- && self . rcm ( ) == other. rcm ( )
590+ // Notes are canonically defined by their commitments.
591+ self . cmu ( ) . eq ( & other. cmu ( ) )
576592 }
577593}
578594
595+ impl Eq for Note { }
596+
579597impl Note {
580598 pub fn uncommitted ( ) -> bls12_381:: Scalar {
581599 // The smallest u-coordinate that is not on the curve
582600 // is one.
583601 bls12_381:: Scalar :: one ( )
584602 }
603+ /// Creates a note from its component parts.
604+ ///
605+ /// # Caveats
606+ ///
607+ /// This low-level constructor enforces that the provided arguments produce an
608+ /// internally valid `Note`. However, it allows notes to be constructed in a way that
609+ /// violates required security checks for note decryption, as specified in
610+ /// [Section 4.19] of the Zcash Protocol Specification. Users of this constructor
611+ /// should only call it with note components that have been fully validated by
612+ /// decrypting a received note according to [Section 4.19].
613+ ///
614+ /// [Section 4.19]: https://zips.z.cash/protocol/protocol.pdf#saplingandorchardinband
615+ pub fn from_parts (
616+ asset_type : AssetType ,
617+ recipient : PaymentAddress ,
618+ value : NoteValue ,
619+ rseed : Rseed ,
620+ ) -> Self {
621+ Note {
622+ asset_type,
623+ recipient,
624+ value,
625+ rseed,
626+ }
627+ }
628+
629+ /// Returns the recipient of this note.
630+ pub fn recipient ( & self ) -> PaymentAddress {
631+ self . recipient
632+ }
633+
634+ /// Returns the value of this note.
635+ pub fn value ( & self ) -> NoteValue {
636+ self . value
637+ }
638+
639+ /// Returns the rseed value of this note.
640+ pub fn rseed ( & self ) -> & Rseed {
641+ & self . rseed
642+ }
585643
586644 /// Computes the note commitment, returning the full point.
587645 fn cm_full_point ( & self ) -> jubjub:: SubgroupPoint {
@@ -592,13 +650,15 @@ impl Note {
592650 note_contents. extend_from_slice ( & self . asset_type . asset_generator ( ) . to_bytes ( ) ) ;
593651
594652 // Writing the value in little endian
595- note_contents. write_u64 :: < LittleEndian > ( self . value ) . unwrap ( ) ;
653+ note_contents
654+ . write_u64 :: < LittleEndian > ( self . value . into ( ) )
655+ . unwrap ( ) ;
596656
597657 // Write g_d
598- note_contents. extend_from_slice ( & self . g_d . to_bytes ( ) ) ;
658+ note_contents. extend_from_slice ( & self . recipient . g_d ( ) . unwrap ( ) . to_bytes ( ) ) ;
599659
600660 // Write pk_d
601- note_contents. extend_from_slice ( & self . pk_d . to_bytes ( ) ) ;
661+ note_contents. extend_from_slice ( & self . recipient . pk_d ( ) . to_bytes ( ) ) ;
602662
603663 assert_eq ! ( note_contents. len( ) , 32 + 32 + 32 + 8 ) ;
604664
@@ -644,6 +704,9 @@ impl Note {
644704 . get_u ( )
645705 }
646706
707+ /// Defined in [Zcash Protocol Spec § 4.7.2: Sending Notes (Sapling)][saplingsend].
708+ ///
709+ /// [saplingsend]: https://zips.z.cash/protocol/protocol.pdf#saplingsend
647710 pub fn rcm ( & self ) -> jubjub:: Fr {
648711 match self . rseed {
649712 Rseed :: BeforeZip212 ( rcm) => rcm,
@@ -653,6 +716,8 @@ impl Note {
653716 }
654717 }
655718
719+ /// Derives `esk` from the internal `Rseed` value, or generates a random value if this
720+ /// note was created with a v1 (i.e. pre-ZIP 212) note plaintext.
656721 pub fn generate_or_derive_esk < R : RngCore + CryptoRng > ( & self , rng : & mut R ) -> jubjub:: Fr {
657722 self . generate_or_derive_esk_internal ( rng)
658723 }
@@ -688,11 +753,11 @@ impl BorshSerialize for Note {
688753 // Write asset type
689754 self . asset_type . serialize ( writer) ?;
690755 // Write note value
691- writer. write_u64 :: < LittleEndian > ( self . value ) ?;
692- // Write diversified base
693- writer. write_all ( & self . g_d . to_bytes ( ) ) ?;
756+ writer. write_u64 :: < LittleEndian > ( self . value ( ) . inner ( ) ) ?;
757+ // Write diversifier
758+ writer. write_all ( & self . recipient ( ) . diversifier ( ) . 0 ) ?;
694759 // Write diversified transmission key
695- writer. write_all ( & self . pk_d . to_bytes ( ) ) ?;
760+ writer. write_all ( & self . recipient ( ) . pk_d ( ) . to_bytes ( ) ) ?;
696761 match self . rseed {
697762 Rseed :: BeforeZip212 ( rcm) => {
698763 // Write note plaintext lead byte
@@ -717,9 +782,10 @@ impl BorshDeserialize for Note {
717782 let asset_type = AssetType :: deserialize ( buf) ?;
718783 // Read note value
719784 let value = buf. read_u64 :: < LittleEndian > ( ) ?;
720- // Read diversified base
721- let g_d_bytes = <[ u8 ; 32 ] >:: deserialize ( buf) ?;
722- let g_d = Option :: from ( jubjub:: SubgroupPoint :: from_bytes ( & g_d_bytes) )
785+ // Read diversifier
786+ let diversifier = Diversifier ( <[ u8 ; 11 ] >:: deserialize ( buf) ?) ;
787+ diversifier
788+ . g_d ( )
723789 . ok_or_else ( || io:: Error :: new ( io:: ErrorKind :: InvalidData , "g_d not in field" ) ) ?;
724790 // Read diversified transmission key
725791 let pk_d_bytes = <[ u8 ; 32 ] >:: deserialize ( buf) ?;
@@ -739,9 +805,8 @@ impl BorshDeserialize for Note {
739805 // Finally construct note object
740806 Ok ( Note {
741807 asset_type,
742- value,
743- g_d,
744- pk_d,
808+ value : NoteValue :: from_raw ( value) ,
809+ recipient : PaymentAddress :: from_parts ( diversifier, pk_d) . unwrap ( ) ,
745810 rseed,
746811 } )
747812 }
@@ -799,13 +864,12 @@ pub mod testing {
799864 prop_compose ! {
800865 pub fn arb_note( value: NoteValue ) (
801866 asset_type in crate :: asset_type:: testing:: arb_asset_type( ) ,
802- addr in arb_payment_address( ) ,
867+ recipient in arb_payment_address( ) ,
803868 rseed in prop:: array:: uniform32( prop:: num:: u8 :: ANY ) . prop_map( Rseed :: AfterZip212 )
804869 ) -> Note {
805870 Note {
806871 value: value. into( ) ,
807- g_d: addr. g_d( ) . unwrap( ) , // this unwrap is safe because arb_payment_address always generates an address with a valid g_d
808- pk_d: * addr. pk_d( ) ,
872+ recipient,
809873 rseed,
810874 asset_type
811875 }
0 commit comments