Merge pull request #291 from p2pderivatives/add-combine-keys

Add combine_keys function to PublicKey
This commit is contained in:
Andrew Poelstra 2021-06-08 18:09:35 +00:00 committed by GitHub
commit e89fd5d269
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 38 additions and 2 deletions

View File

@ -65,6 +65,7 @@ pub const ONE_KEY: SecretKey = SecretKey([0, 0, 0, 0, 0, 0, 0, 0,
/// A Secp256k1 public key, used for verification of signatures /// A Secp256k1 public key, used for verification of signatures
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
#[repr(transparent)]
pub struct PublicKey(ffi::PublicKey); pub struct PublicKey(ffi::PublicKey);
impl fmt::LowerHex for PublicKey { impl fmt::LowerHex for PublicKey {
@ -389,14 +390,26 @@ impl PublicKey {
/// the result would be the point at infinity, i.e. we are adding this point /// the result would be the point at infinity, i.e. we are adding this point
/// to its own negation /// to its own negation
pub fn combine(&self, other: &PublicKey) -> Result<PublicKey, Error> { pub fn combine(&self, other: &PublicKey) -> Result<PublicKey, Error> {
PublicKey::combine_keys(&[self, other])
}
/// Adds the keys in the provided slice together, returning the sum. Returns
/// an error if the result would be the point at infinity, i.e. we are adding
/// a point to its own negation
pub fn combine_keys(keys: &[&PublicKey]) -> Result<PublicKey, Error> {
use core::mem::transmute;
use core::i32::MAX;
debug_assert!(keys.len() < MAX as usize);
unsafe { unsafe {
let mut ret = ffi::PublicKey::new(); let mut ret = ffi::PublicKey::new();
let ptrs = [self.as_c_ptr(), other.as_c_ptr()]; let ptrs : &[*const ffi::PublicKey] =
transmute::<&[&PublicKey], &[*const ffi::PublicKey]>(keys);
if ffi::secp256k1_ec_pubkey_combine( if ffi::secp256k1_ec_pubkey_combine(
ffi::secp256k1_context_no_precomp, ffi::secp256k1_context_no_precomp,
&mut ret, &mut ret,
ptrs.as_c_ptr(), ptrs.as_c_ptr(),
2 keys.len() as i32
) == 1 ) == 1
{ {
Ok(PublicKey(ret)) Ok(PublicKey(ret))
@ -848,6 +861,29 @@ mod test {
assert_eq!(sum1.unwrap(), exp_sum); assert_eq!(sum1.unwrap(), exp_sum);
} }
#[test]
fn pubkey_combine_keys() {
let compressed1 = PublicKey::from_slice(
&hex!("0241cc121c419921942add6db6482fb36243faf83317c866d2a28d8c6d7089f7ba"),
).unwrap();
let compressed2 = PublicKey::from_slice(
&hex!("02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443"),
).unwrap();
let compressed3 = PublicKey::from_slice(
&hex!("03e74897d8644eb3e5b391ca2ab257aec2080f4d1a95cad57e454e47f021168eb0")
).unwrap();
let exp_sum = PublicKey::from_slice(
&hex!("0252d73a47f66cf341e5651542f0348f452b7c793af62a6d8bff75ade703a451ad"),
).unwrap();
let sum1 = PublicKey::combine_keys(&[&compressed1, &compressed2, &compressed3]);
assert!(sum1.is_ok());
let sum2 = PublicKey::combine_keys(&[&compressed1, &compressed2, &compressed3]);
assert!(sum2.is_ok());
assert_eq!(sum1, sum2);
assert_eq!(sum1.unwrap(), exp_sum);
}
#[test] #[test]
fn pubkey_equal() { fn pubkey_equal() {
let pk1 = PublicKey::from_slice( let pk1 = PublicKey::from_slice(