Skip to content

Commit e89fd5d

Browse files
authored
Merge pull request #291 from p2pderivatives/add-combine-keys
Add combine_keys function to PublicKey
2 parents a5dfd09 + 7d32182 commit e89fd5d

File tree

1 file changed

+38
-2
lines changed

1 file changed

+38
-2
lines changed

src/key.rs

+38-2
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ pub const ONE_KEY: SecretKey = SecretKey([0, 0, 0, 0, 0, 0, 0, 0,
6565

6666
/// A Secp256k1 public key, used for verification of signatures
6767
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
68+
#[repr(transparent)]
6869
pub struct PublicKey(ffi::PublicKey);
6970

7071
impl fmt::LowerHex for PublicKey {
@@ -389,14 +390,26 @@ impl PublicKey {
389390
/// the result would be the point at infinity, i.e. we are adding this point
390391
/// to its own negation
391392
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);
392404
unsafe {
393405
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);
395408
if ffi::secp256k1_ec_pubkey_combine(
396409
ffi::secp256k1_context_no_precomp,
397410
&mut ret,
398411
ptrs.as_c_ptr(),
399-
2
412+
keys.len() as i32
400413
) == 1
401414
{
402415
Ok(PublicKey(ret))
@@ -848,6 +861,29 @@ mod test {
848861
assert_eq!(sum1.unwrap(), exp_sum);
849862
}
850863

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+
851887
#[test]
852888
fn pubkey_equal() {
853889
let pk1 = PublicKey::from_slice(

0 commit comments

Comments
 (0)