|
17 | 17 |
|
18 | 18 | #[cfg(any(test, feature = "rand"))] use rand::Rng;
|
19 | 19 |
|
20 |
| -use std::fmt; |
| 20 | +use std::{fmt, mem}; |
21 | 21 |
|
22 | 22 | use super::{Secp256k1};
|
23 | 23 | use super::Error::{self, InvalidPublicKey, InvalidSecretKey};
|
@@ -273,6 +273,21 @@ impl PublicKey {
|
273 | 273 | }
|
274 | 274 | }
|
275 | 275 | }
|
| 276 | + |
| 277 | + /// Adds a second key to this one, returning the sum. Returns an error if |
| 278 | + /// the result would be the point at infinity, i.e. we are adding this point |
| 279 | + /// to its own negation |
| 280 | + pub fn combine<C>(&self, secp: &Secp256k1<C>, other: &PublicKey) -> Result<PublicKey, Error> { |
| 281 | + unsafe { |
| 282 | + let mut ret = mem::uninitialized(); |
| 283 | + let ptrs = [self.as_ptr(), other.as_ptr()]; |
| 284 | + if ffi::secp256k1_ec_pubkey_combine(secp.ctx, &mut ret, ptrs.as_ptr(), 2) == 1 { |
| 285 | + Ok(PublicKey(ret)) |
| 286 | + } else { |
| 287 | + Err(InvalidPublicKey) |
| 288 | + } |
| 289 | + } |
| 290 | + } |
276 | 291 | }
|
277 | 292 |
|
278 | 293 | /// Creates a new public key from a FFI public key
|
@@ -551,6 +566,30 @@ mod test {
|
551 | 566 | assert_eq!(count, COUNT);
|
552 | 567 | }
|
553 | 568 |
|
| 569 | + #[test] |
| 570 | + fn pubkey_combine() { |
| 571 | + let s = Secp256k1::without_caps(); |
| 572 | + let compressed1 = PublicKey::from_slice( |
| 573 | + &s, |
| 574 | + &hex!("0241cc121c419921942add6db6482fb36243faf83317c866d2a28d8c6d7089f7ba"), |
| 575 | + ).unwrap(); |
| 576 | + let compressed2 = PublicKey::from_slice( |
| 577 | + &s, |
| 578 | + &hex!("02e6642fd69bd211f93f7f1f36ca51a26a5290eb2dd1b0d8279a87bb0d480c8443"), |
| 579 | + ).unwrap(); |
| 580 | + let exp_sum = PublicKey::from_slice( |
| 581 | + &s, |
| 582 | + &hex!("0384526253c27c7aef56c7b71a5cd25bebb66dddda437826defc5b2568bde81f07"), |
| 583 | + ).unwrap(); |
| 584 | + |
| 585 | + let sum1 = compressed1.combine(&s, &compressed2); |
| 586 | + assert!(sum1.is_ok()); |
| 587 | + let sum2 = compressed2.combine(&s, &compressed1); |
| 588 | + assert!(sum2.is_ok()); |
| 589 | + assert_eq!(sum1, sum2); |
| 590 | + assert_eq!(sum1.unwrap(), exp_sum); |
| 591 | + } |
| 592 | + |
554 | 593 | #[test]
|
555 | 594 | fn pubkey_equal() {
|
556 | 595 | let s = Secp256k1::new();
|
|
0 commit comments