Skip to content

Commit d0a51bb

Browse files
committed
feat(silentpayments): add recipient label support
1 parent 8efb0a6 commit d0a51bb

File tree

3 files changed

+159
-0
lines changed

3 files changed

+159
-0
lines changed

secp256k1-sys/src/lib.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -939,8 +939,34 @@ pub mod silentpayments {
939939
plain_seckeys: *const *const c_uchar,
940940
n_plain_seckeys: size_t,
941941
) -> c_int;
942+
943+
#[cfg_attr(
944+
not(rust_secp_no_symbol_renaming),
945+
link_name = "rustsecp256k1_v0_13_silentpayments_recipient_create_label"
946+
)]
947+
pub fn secp256k1_silentpayments_recipient_create_label(
948+
ctx: *const Context,
949+
label: *mut PublicKey,
950+
label_tweak32: *mut c_uchar,
951+
scan_key32: *const c_uchar,
952+
m: c_uint,
953+
) -> c_int;
954+
955+
#[cfg_attr(
956+
not(rust_secp_no_symbol_renaming),
957+
link_name = "rustsecp256k1_v0_13_silentpayments_recipient_create_labeled_spend_pubkey"
958+
)]
959+
pub fn secp256k1_silentpayments_recipient_create_labeled_spend_pubkey(
960+
ctx: *const Context,
961+
labeled_spend_pubkey: *mut PublicKey,
962+
unlabeled_spend_pubkey: *const PublicKey,
963+
label: *const PublicKey,
964+
) -> c_int;
942965
}
943966

967+
pub type LabelLookup =
968+
Option<unsafe extern "C" fn(*const c_uchar, *const c_void) -> *const c_uchar>;
969+
944970
#[repr(C)]
945971
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
946972
pub struct Recipient {

src/silentpayments/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
pub mod recipient;
12
pub mod sender;

src/silentpayments/recipient.rs

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
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

Comments
 (0)