@@ -585,6 +585,7 @@ int secp256k1_silentpayments_recipient_scan_outputs(
585585 secp256k1_xonly_pubkey output_xonly ;
586586 unsigned char shared_secret [33 ];
587587 const unsigned char * label_tweak = NULL ;
588+ unsigned char * is_found = NULL ;
588589 size_t i , j , k , n_found , found_idx ;
589590 int found , combined , valid_scan_key , ret ;
590591
@@ -624,6 +625,13 @@ int secp256k1_silentpayments_recipient_scan_outputs(
624625 /* Clear the scan_key_scalar since we no longer need it and leaking this value would break indistinguishability of the transaction. */
625626 secp256k1_scalar_clear (& scan_key_scalar );
626627
628+ /* Allocate tracking array to skip already-matched outputs */
629+ is_found = (unsigned char * )calloc (n_tx_outputs , sizeof (unsigned char ));
630+ if (!is_found ) {
631+ secp256k1_memclear_explicit (shared_secret , sizeof (shared_secret ));
632+ return 0 ;
633+ }
634+
627635 found_idx = 0 ;
628636 n_found = 0 ;
629637 k = 0 ;
@@ -637,6 +645,7 @@ int secp256k1_silentpayments_recipient_scan_outputs(
637645 if (!secp256k1_silentpayments_create_output_tweak (& output_tweak_scalar , shared_secret , k )) {
638646 secp256k1_scalar_clear (& output_tweak_scalar );
639647 secp256k1_memclear_explicit (& shared_secret , sizeof (shared_secret ));
648+ free (is_found );
640649 return 0 ;
641650 }
642651
@@ -647,11 +656,13 @@ int secp256k1_silentpayments_recipient_scan_outputs(
647656 /* Leaking these values would break indistinguishability of the transaction, so clear them. */
648657 secp256k1_scalar_clear (& output_tweak_scalar );
649658 secp256k1_memclear_explicit (& shared_secret , sizeof (shared_secret ));
659+ free (is_found );
650660 return 0 ;
651661 }
652662 found = 0 ;
653663 secp256k1_xonly_pubkey_save (& output_xonly , & output_ge );
654664 for (j = 0 ; j < n_tx_outputs ; j ++ ) {
665+ if (is_found [j ]) continue ; /* Skip already-matched outputs */
655666 if (secp256k1_xonly_pubkey_cmp (ctx , & output_xonly , tx_outputs [j ]) == 0 ) {
656667 label_tweak = NULL ;
657668 found = 1 ;
@@ -711,6 +722,7 @@ int secp256k1_silentpayments_recipient_scan_outputs(
711722 }
712723 }
713724 if (found ) {
725+ is_found [found_idx ] = 1 ; /* Mark this output as matched */
714726 found_outputs [n_found ]-> output = * tx_outputs [found_idx ];
715727 secp256k1_scalar_get_b32 (found_outputs [n_found ]-> tweak , & output_tweak_scalar );
716728 /* Clear the output_tweak_scalar since we no longer need it and leaking this value would
@@ -747,6 +759,7 @@ int secp256k1_silentpayments_recipient_scan_outputs(
747759 if (k < UINT32_MAX ) {
748760 k ++ ;
749761 } else {
762+ free (is_found );
750763 return 0 ;
751764 }
752765 } else {
@@ -758,6 +771,7 @@ int secp256k1_silentpayments_recipient_scan_outputs(
758771
759772 /* Leaking the shared_secret would break indistinguishability of the transaction, so clear it. */
760773 secp256k1_memclear_explicit (shared_secret , sizeof (shared_secret ));
774+ free (is_found );
761775 return 1 ;
762776}
763777
0 commit comments