-
Notifications
You must be signed in to change notification settings - Fork 264
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Add bip352 silentpayments module #721
base: master
Are you sure you want to change the base?
Conversation
This modification allows running the command `./vendor-libsecp.sh -f pull/1519/head` to obtain MuSig2 components from `bitcoin-core/secp256k1`. This commit may be discarded after merging PR #1519.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool! Concept ACK.
ec34fda
to
c217147
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for picking this up!
src/constants.rs
Outdated
@@ -33,6 +33,9 @@ pub const KEY_PAIR_SIZE: usize = 96; | |||
/// The size of a full ElligatorSwift encoding. | |||
pub const ELLSWIFT_ENCODING_SIZE: usize = 64; | |||
|
|||
/// The size of a silent payment public data. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in 0e7e062 ("Add Silent Payments module"):
nit: "silent payments"
/// The size of a silent payment public data. | |
/// The size of a silent payments public data object. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review. Done !
pub fn silentpayments_sender_create_outputs<C: Verification>( | ||
secp: &Secp256k1<C>, | ||
recipients: &[SilentpaymentsRecipient], | ||
smallest_outpoint: &[u8; 36], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in 0e7e062 ("lib: Add Silent Payments module"):
Would it make sense to use an Outpoint
type here (assuming one exists)? On the one hand, it makes things more clear and less foot gunny for the caller, on the other hand I can see an argument for having the rust-secp256k1 crate be unaware of Bitcoin protocol specifics.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds like we should wait for bitcoin-primitives
to be released and gate this behind an optional dependency on it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had a massive brainfart here. We want to optionally use crypto
in primitives
which will optionally depend on secp256k1
, so secp256k1
cannot (optionally) depend on primitives
as it'd create a cycle if all features are on. I'm not sure what the best solution is but having silent payments implemented outside secp256k1
sounds most appealing at first thought.
src/silentpayments.rs
Outdated
/// Creates an `SilentpaymentsPublicData` object from a 98-byte array. | ||
pub fn from_array(data: [u8; 98]) -> SilentpaymentsPublicData { | ||
SilentpaymentsPublicData(ffi::SilentpaymentsPublicData::from_array(data)) | ||
} | ||
|
||
/// Returns the 64-byte array representation of this `SilentpaymentsPublicData` object. | ||
pub fn to_array(&self) -> [u8; 98] { self.0.to_array() } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in 0e7e062 ("lib: Add Silent Payments module"):
How do you foresee the to_array/from_array functions being used? public_data
is meant to be an opaque data type, so it seems better to me to not have these methods and instead have callers always use the create
and serialize
functions, but perhaps I'm missing something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch ! Done.
c217147
to
36b2c6b
Compare
Removed dynamically sized vector in most functions and simplified the code.
|
# only used in the example of silent payments | ||
libc = { version = "0.2", optional = true } | ||
cc = { version = "1.0", optional = true } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dev dependencies may be used in examples, so these can be put there. (https://doc.rust-lang.org/rust-by-example/testing/dev_dependencies.html)
unsafe { | ||
// Get a pointer to the inner ffi::PublicKey | ||
let ffi_pubkey_ptr: *const ffi::PublicKey = pubkey.as_c_ptr(); | ||
|
||
// Dereference the pointer to get the ffi::PublicKey | ||
// Then create a copy of it | ||
(*ffi_pubkey_ptr).clone() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unnecessary unsafe
and clone
, PublicKey
wraps ffi::PublicKey
and they are both Copy
.
for (i, pubkey) in out_pubkeys.iter_mut().enumerate() { | ||
out_pubkeys_ptrs[i] = pubkey as *mut _; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks redundant, doesn't out_pubkeys.iter_mut().map(|k| k as *mut _).collect()
(line 81) do the same?
|
||
let (ffi_taproot_seckeys, n_taproot_seckeys) = match taproot_seckeys { | ||
Some(keys) => { | ||
let ffi_keys: &[*const ffi::Keypair] = transmute::<&[&Keypair], &[*const ffi::Keypair]>(taproot_seckeys.unwrap()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pointer casting is recommended over transmuting pointers and references, but both approaches are unsound if Keypair
is not guaranteed to have the same layout as ffi::Keypair
. Adding #[repr(transparent)]
to Keypair
fixes this.
Same comment for SecretKey
a few lines down, and some more in this file, please check all uses of transmute
and use pointer casting where possible, and review if the source and destination type are layout-compatible.
); | ||
|
||
if res == 1 { | ||
Ok(out_pubkeys.into_iter().map(XOnlyPublicKey::from).collect()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be optimized if XOnlyPublicKey
is #[repr(transparent)]
. (using Vec::from_raw_parts)
return Ok(LabelTweakResult { pubkey, label_tweak }); | ||
} else { | ||
return Err(LabelTweakError::Failure); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Syntax could be more "rusty" by removing the 'return' keywords (this is a clippy warning, see other clippy warnings for more simple improvements like this)
unsafe { | ||
|
||
let empty_data = [0u8; constants::SILENT_PAYMENTS_PUBLIC_DATA_SIZE]; | ||
let mut silentpayments_public_data = ffi::SilentpaymentsPublicData::from_array(empty_data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can use Self::new()
, and as_mut_c_ptr()
for the c function. It then does not need to be wrapped before returning.
Same comment for line 308.
let mut result = vec![SilentpaymentsFoundOutput::empty(); n_found_outputs]; | ||
|
||
for i in 0..n_found_outputs { | ||
result[i] = SilentpaymentsFoundOutput(out_found_output[i]); | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be optimized to use Vec::from_raw_parts
if SilentpaymentsFoundOutput
is made #[repr(transparent)]
.
label_lookup: SilentpaymentsLabelLookupFunction, | ||
label_context: L, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This requires users to use unsafe, and is maybe even unsound to accept a function that can return pointers to a "safe" (not annotated unsafe) function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is also unsound on Rust < 1.81, see https://blog.rust-lang.org/2024/09/05/Rust-1.81.0.html#abort-on-uncaught-panics-in-extern-c-functions. To fix that you have to catch_unwind
and abort
manually when using older versions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I managed to create a safe abstraction for this callback (given the current restrictions, which might change as bitcoin-core/secp256k1#1519 is not merged yet). I added it (2b3f633) to a branch on my fork, feel free to add (may be modified) it here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @antonilol for all your contributions, here and to other projects like electrs! They are very helpful.
This PR adds bip352
silentpayments
module based on bitcoin-core/secp256k1#1519.Currently, it creates bindings for all silent payment structs and functions and also adds the high-level API to access them.
examples/silentpayments.rs
implements the same example asexamples/silentpayments.c
from the original repository and shows how to use all functions.The example can be run with
cargo run --example silentpayments --features="rand std libc cc"
.Although it implements all the features of the
silentpayments
module, this is still a work in progress, as the current module only works with the standard library.For review purposes, only the last three commits matter. The others may be discarded after the module is merged into the original repository and the
depend
folder updated.