@@ -65,6 +65,7 @@ pub const ONE_KEY: SecretKey = SecretKey([0, 0, 0, 0, 0, 0, 0, 0,
65
65
66
66
/// A Secp256k1 public key, used for verification of signatures
67
67
#[ derive( Copy , Clone , PartialEq , Eq , Debug , Hash ) ]
68
+ #[ repr( transparent) ]
68
69
pub struct PublicKey ( ffi:: PublicKey ) ;
69
70
70
71
impl fmt:: LowerHex for PublicKey {
@@ -389,14 +390,26 @@ impl PublicKey {
389
390
/// the result would be the point at infinity, i.e. we are adding this point
390
391
/// to its own negation
391
392
pub fn combine ( & self , other : & PublicKey ) -> Result < PublicKey , Error > {
393
+ PublicKey :: combine_keys ( & [ self , other] )
394
+ }
395
+
396
+ /// Adds the keys in the provided slice together, returning the sum. Returns
397
+ /// an error if the result would be the point at infinity, i.e. we are adding
398
+ /// a point to its own negation
399
+ pub fn combine_keys ( keys : & [ & PublicKey ] ) -> Result < PublicKey , Error > {
400
+ use core:: mem:: transmute;
401
+ use core:: i32:: MAX ;
402
+
403
+ debug_assert ! ( keys. len( ) < MAX as usize ) ;
392
404
unsafe {
393
405
let mut ret = ffi:: PublicKey :: new ( ) ;
394
- let ptrs = [ self . as_c_ptr ( ) , other. as_c_ptr ( ) ] ;
406
+ let ptrs : & [ * const ffi:: PublicKey ] =
407
+ transmute :: < & [ & PublicKey ] , & [ * const ffi:: PublicKey ] > ( keys) ;
395
408
if ffi:: secp256k1_ec_pubkey_combine (
396
409
ffi:: secp256k1_context_no_precomp,
397
410
& mut ret,
398
411
ptrs. as_c_ptr ( ) ,
399
- 2
412
+ keys . len ( ) as i32
400
413
) == 1
401
414
{
402
415
Ok ( PublicKey ( ret) )
@@ -848,6 +861,29 @@ mod test {
848
861
assert_eq ! ( sum1. unwrap( ) , exp_sum) ;
849
862
}
850
863
864
+ #[ test]
865
+ fn pubkey_combine_keys ( ) {
866
+ let compressed1 = PublicKey :: from_slice (
867
+ & hex ! ( "0241cc121c419921942add6db6482fb36243faf83317c866d2a28d8c6d7089f7ba" ) ,
868
+ ) . unwrap ( ) ;
869
+ let compressed2 = PublicKey :: from_slice (
870
+ & hex ! ( "02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443" ) ,
871
+ ) . unwrap ( ) ;
872
+ let compressed3 = PublicKey :: from_slice (
873
+ & hex ! ( "03e74897d8644eb3e5b391ca2ab257aec2080f4d1a95cad57e454e47f021168eb0" )
874
+ ) . unwrap ( ) ;
875
+ let exp_sum = PublicKey :: from_slice (
876
+ & hex ! ( "0252d73a47f66cf341e5651542f0348f452b7c793af62a6d8bff75ade703a451ad" ) ,
877
+ ) . unwrap ( ) ;
878
+
879
+ let sum1 = PublicKey :: combine_keys ( & [ & compressed1, & compressed2, & compressed3] ) ;
880
+ assert ! ( sum1. is_ok( ) ) ;
881
+ let sum2 = PublicKey :: combine_keys ( & [ & compressed1, & compressed2, & compressed3] ) ;
882
+ assert ! ( sum2. is_ok( ) ) ;
883
+ assert_eq ! ( sum1, sum2) ;
884
+ assert_eq ! ( sum1. unwrap( ) , exp_sum) ;
885
+ }
886
+
851
887
#[ test]
852
888
fn pubkey_equal ( ) {
853
889
let pk1 = PublicKey :: from_slice (
0 commit comments