@@ -490,6 +490,7 @@ mod tests {
490490 } ;
491491 use crate :: {
492492 note:: asset_base:: testing:: arb_asset_base, note:: AssetBase , primitives:: redpallas,
493+ value:: NoteValue ,
493494 } ;
494495
495496 fn negate_value_sum ( value : ValueSum ) -> ValueSum {
@@ -503,20 +504,46 @@ mod tests {
503504 ValueSum :: from_magnitude_sign ( magnitude, neg_sign)
504505 }
505506
507+ fn arb_asset_values_balanced_per_asset (
508+ bound : NoteValue ,
509+ n_assets : usize ,
510+ ) -> impl Strategy < Value = Vec < ( ValueSum , ValueCommitTrapdoor , AssetBase ) > > {
511+ (
512+ prop:: collection:: vec ( arb_asset_base ( ) , n_assets) ,
513+ prop:: collection:: vec ( arb_value_sum_bounded ( bound) , n_assets * 4 ) ,
514+ prop:: collection:: vec ( arb_trapdoor ( ) , n_assets * 5 ) ,
515+ )
516+ . prop_map ( move |( assets, vals, traps) | {
517+ let mut traps = traps. into_iter ( ) ;
518+ let mut out = Vec :: with_capacity ( n_assets * 5 ) ;
519+
520+ for ( asset, four_values) in assets. into_iter ( ) . zip ( vals. chunks_exact ( 4 ) ) {
521+ let sum = four_values
522+ . iter ( )
523+ . cloned ( )
524+ . sum :: < Result < ValueSum , OverflowError > > ( )
525+ . expect ( "we generate values that won't overflow" ) ;
526+
527+ let fifth = negate_value_sum ( sum) ;
528+
529+ // Four random entries
530+ for value in four_values. iter ( ) . cloned ( ) {
531+ out. push ( ( value, traps. next ( ) . expect ( "enough trapdoors" ) , asset) ) ;
532+ }
533+
534+ // One balancing entry so that the per-asset balance is zero
535+ out. push ( ( fifth, traps. next ( ) . expect ( "enough trapdoors" ) , asset) ) ;
536+ }
537+
538+ out
539+ } )
540+ }
541+
506542 fn check_binding_signature (
507543 native_values : & [ ( ValueSum , ValueCommitTrapdoor ) ] ,
508544 arb_values : & [ ( ValueSum , ValueCommitTrapdoor , AssetBase ) ] ,
509- neg_trapdoors : & [ ValueCommitTrapdoor ] ,
510545 arb_values_to_burn : & [ ( ValueSum , ValueCommitTrapdoor , AssetBase ) ] ,
511546 ) {
512- // for each arb value, create a negative value with a different trapdoor
513- let neg_arb_values: Vec < _ > = arb_values
514- . iter ( )
515- . cloned ( )
516- . zip ( neg_trapdoors. iter ( ) . cloned ( ) )
517- . map ( |( ( value, _, asset) , rcv) | ( negate_value_sum ( value) , rcv, asset) )
518- . collect ( ) ;
519-
520547 let native_value_balance = native_values
521548 . iter ( )
522549 . map ( |( value, _) | value)
@@ -529,13 +556,7 @@ mod tests {
529556 . map ( |( value_sum, trapdoor) | ( * value_sum, trapdoor. clone ( ) , AssetBase :: native ( ) ) )
530557 . collect ( ) ;
531558
532- let values = [
533- & native_values_with_asset,
534- arb_values,
535- & neg_arb_values,
536- arb_values_to_burn,
537- ]
538- . concat ( ) ;
559+ let values = [ & native_values_with_asset, arb_values, arb_values_to_burn] . concat ( ) ;
539560
540561 let bsk = values
541562 . iter ( )
@@ -571,20 +592,23 @@ mod tests {
571592 prop:: collection:: vec( ( arb_value_sum_bounded( bound) , arb_trapdoor( ) ) , n_values)
572593 )
573594 ) ,
574- ( asset_values, neg_trapdoors) in ( 1usize ..10 ) . prop_flat_map( |n_values|
575- ( arb_note_value_bounded( MAX_NOTE_VALUE / n_values as u64 ) . prop_flat_map( move |bound|
576- prop:: collection:: vec( ( arb_value_sum_bounded( bound) , arb_trapdoor( ) , arb_asset_base( ) ) , n_values)
577- ) , prop:: collection:: vec( arb_trapdoor( ) , n_values) )
595+ // An Orchard ZSA transaction is valid only if the balance of each custom asset is zero.
596+ // Accordingly, for each custom asset we generate 5 random ValueSum values (possibly negative)
597+ // that sum to zero.
598+ asset_values in ( 1usize ..10 ) . prop_flat_map( |n_assets|
599+ arb_note_value_bounded( MAX_NOTE_VALUE / ( n_assets as u64 * 5 ) ) . prop_flat_map( move |bound|
600+ arb_asset_values_balanced_per_asset( bound, n_assets)
601+ )
578602 ) ,
579603 burn_values in ( 1usize ..10 ) . prop_flat_map( |n_values|
580604 arb_note_value_bounded( MAX_NOTE_VALUE / n_values as u64 )
581605 . prop_flat_map( move |bound| prop:: collection:: vec( ( arb_value_sum_bounded( bound) , arb_trapdoor( ) , arb_asset_base( ) ) , n_values) )
582606 )
583607 ) {
584- check_binding_signature( & native_values, & [ ] , & [ ] , & [ ] ) ;
585- check_binding_signature( & native_values, & [ ] , & [ ] , & burn_values) ;
586- check_binding_signature( & native_values, & asset_values, & neg_trapdoors , & [ ] ) ;
587- check_binding_signature( & native_values, & asset_values, & neg_trapdoors , & burn_values) ;
608+ check_binding_signature( & native_values, & [ ] , & [ ] ) ;
609+ check_binding_signature( & native_values, & [ ] , & burn_values) ;
610+ check_binding_signature( & native_values, & asset_values, & [ ] ) ;
611+ check_binding_signature( & native_values, & asset_values, & burn_values) ;
588612 }
589613 }
590614}
0 commit comments