|
| 1 | +//! Provide all the binding functions and methods to be used from the perspective of the |
| 2 | +//! silentpayments recipient. |
| 3 | +use crate::ffi::{self, CPtr}; |
| 4 | +use crate::{PublicKey, Secp256k1, SecretKey}; |
| 5 | + |
| 6 | +/// Error creating label tweak. |
| 7 | +#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)] |
| 8 | +pub struct LabelTweakCreationError; |
| 9 | + |
| 10 | +#[cfg(feature = "std")] |
| 11 | +impl std::error::Error for LabelTweakCreationError {} |
| 12 | + |
| 13 | +impl core::fmt::Display for LabelTweakCreationError { |
| 14 | + fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> { |
| 15 | + match self { |
| 16 | + LabelTweakCreationError => write!(f, "Failed to create label tweak"), |
| 17 | + } |
| 18 | + } |
| 19 | +} |
| 20 | + |
| 21 | +/// Create Silent Payment label tweak and label. |
| 22 | +/// |
| 23 | +/// Given a recipient's scan [`SecretKey`] and a label integer m, calculate the |
| 24 | +/// corresponding label tweak and label: |
| 25 | +/// |
| 26 | +/// label_tweak = hash(scan_key || m) |
| 27 | +/// label = label_tweak * G |
| 28 | +/// |
| 29 | +/// # Arguments |
| 30 | +/// * `scan_seckey` - the recipient's scan [`SecretKey`]. |
| 31 | +/// * `m` - a label integer for the m-th label (0 is used for change outputs). |
| 32 | +/// |
| 33 | +/// # Returns |
| 34 | +/// A tuple ([`PublicKey`], [u8; 32]) where the first element is the label public key and the |
| 35 | +/// second is the label tweak. |
| 36 | +/// |
| 37 | +/// # Errors |
| 38 | +/// * [`LabelTweakCreationError`] - if label tweak is not a valid scalar (negligible probability per hash evaluation). |
| 39 | +pub fn create_label( |
| 40 | + scan_seckey: &SecretKey, |
| 41 | + m: u32, |
| 42 | +) -> Result<(PublicKey, [u8; 32]), LabelTweakCreationError> { |
| 43 | + unsafe { |
| 44 | + let mut label = ffi::PublicKey::new(); |
| 45 | + let mut label_tweak32 = [0u8; 32]; |
| 46 | + |
| 47 | + let res = crate::with_global_context( |
| 48 | + |secp: &Secp256k1<crate::AllPreallocated>| { |
| 49 | + ffi::silentpayments::secp256k1_silentpayments_recipient_create_label( |
| 50 | + secp.ctx().as_ptr(), |
| 51 | + &mut label, |
| 52 | + label_tweak32.as_mut_c_ptr(), |
| 53 | + scan_seckey.as_c_ptr(), |
| 54 | + m, |
| 55 | + ) |
| 56 | + }, |
| 57 | + None, |
| 58 | + ); |
| 59 | + |
| 60 | + if res == 1 { |
| 61 | + let label = PublicKey::from(label); |
| 62 | + Ok((label, label_tweak32)) |
| 63 | + } else { |
| 64 | + Err(LabelTweakCreationError) |
| 65 | + } |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +/// Failed to create labeled spend pubkey. |
| 70 | +#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)] |
| 71 | +pub struct LabeledSpendPubkeyCreationError; |
| 72 | + |
| 73 | +#[cfg(feature = "std")] |
| 74 | +impl std::error::Error for LabeledSpendPubkeyCreationError {} |
| 75 | + |
| 76 | +impl core::fmt::Display for LabeledSpendPubkeyCreationError { |
| 77 | + fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> { |
| 78 | + match self { |
| 79 | + LabeledSpendPubkeyCreationError => { |
| 80 | + write!(f, "Failed to create labeled spend pubkey") |
| 81 | + } |
| 82 | + } |
| 83 | + } |
| 84 | +} |
| 85 | + |
| 86 | +/// Create Silent Payment labeled spend public key. |
| 87 | +/// |
| 88 | +/// Given a recipient's spend public key and a label, calculate the |
| 89 | +/// corresponding labeled spend public key: |
| 90 | +/// |
| 91 | +/// labeled_spend_pubkey = unlabeled_spend_pubkey + label |
| 92 | +/// |
| 93 | +/// The result is used by the recipient to create a Silent Payment address, |
| 94 | +/// consisting of the serialized and concatenated scan public key and |
| 95 | +/// (labeled) spend public key. |
| 96 | +/// |
| 97 | +/// # Arguments: |
| 98 | +/// * `unlabeled_spend_pubkey` - the recipient's unlabeled spend public key to label. |
| 99 | +/// * `label` - the recipient's label public key. |
| 100 | +/// |
| 101 | +/// # Returns |
| 102 | +/// The resulting labeled [`PublicKey`]. |
| 103 | +/// |
| 104 | +/// # Errors |
| 105 | +/// * [`LabeledSpendPubkeyCreationError`] - if spend pubkey and label sum to zero (negligible probability for labels created according to BIP352). |
| 106 | +pub fn create_labeled_spend_pubkey( |
| 107 | + unlabeled_spend_pubkey: &PublicKey, |
| 108 | + label: &PublicKey, |
| 109 | +) -> Result<PublicKey, LabeledSpendPubkeyCreationError> { |
| 110 | + unsafe { |
| 111 | + let mut pubkey = ffi::PublicKey::new(); |
| 112 | + |
| 113 | + let res = crate::with_global_context( |
| 114 | + |secp: &Secp256k1<crate::AllPreallocated>| { |
| 115 | + ffi::silentpayments::secp256k1_silentpayments_recipient_create_labeled_spend_pubkey( |
| 116 | + secp.ctx().as_ptr(), |
| 117 | + &mut pubkey, |
| 118 | + unlabeled_spend_pubkey.as_c_ptr(), |
| 119 | + label.as_c_ptr(), |
| 120 | + ) |
| 121 | + }, |
| 122 | + None, |
| 123 | + ); |
| 124 | + |
| 125 | + if res == 1 { |
| 126 | + let pubkey = PublicKey::from(pubkey); |
| 127 | + Ok(pubkey) |
| 128 | + } else { |
| 129 | + Err(LabeledSpendPubkeyCreationError) |
| 130 | + } |
| 131 | + } |
| 132 | +} |
0 commit comments