add posibility to create SharedSecret with applied custom hash function#164
add posibility to create SharedSecret with applied custom hash function#164shmishleniy wants to merge 1 commit into
Conversation
|
Can you please share the use case on using a different hash function here? |
|
Hi,
First step is broken now. We will use ffi::secp256k1_ecdh(..) directly to create unencrypted shared. |
|
here is current implementation
|
|
concept ACK. There were a few usecases listed when we added this support upstream (and we took forever on that ... let's try to be faster in rust-secp :)). I'm very nervous about this business of casting a rust closure to a |
|
We are trying to get decommission our fork of The "raw" variant is used in |
|
I have not reviewed this thoroughly but I'm pretty sure closures can't be safely casted to fn pointers. You need an https://rust-lang.github.io/unsafe-code-guidelines/layout/function-pointers.html Fn traits don't promise to be function pointers. They are just types that impl the trait. |
|
I just realized I misunderstood the code. the FnMut trait is used as data. so C code never dereference it. Then I think that code is completely valid (though I'm not sure if I like it yet) for the following reasons:
[1] https://play.rust-lang.org/?gist=cac9fbb4766cfda4be5f9bbefc0a0878 |
Maybe this SO post is relevant to this? Seems to suggest that as long as C doesn't do anything funny with the pointer it should be fine. Sure would be nice to see more "official" documentation asserting that though. |
|
Given that this is a Rust library, wouldn't it be much cleaner to expect a Rust function instead of a C function? Then we simply need a C function that passes us x and y, and then we apply a user-provided Rust function to x and y. The Rust function can take x and y as bytestrings. |
| where F: FnMut(&mut [u8], &[u8], &[u8]) -> i32 | ||
| { | ||
| extern "C" fn hash_callback<F>(output: *mut c_uchar, x: *const c_uchar, y: *const c_uchar, data: *const c_void) -> c_int | ||
| where F: FnMut(&mut [u8], &[u8], &[u8]) -> i32 |
There was a problem hiding this comment.
I would consider actually using i16 here. and casting it to c_int in the function. that way it should be compatible with any rust supporting architecture while being lossless.
| unsafe { (*callback)(from_raw_parts_mut(output, 32), from_raw_parts(x, 32), from_raw_parts(y, 32)) } | ||
| } | ||
| unsafe { | ||
| let mut ss = ffi::SharedSecret::new(); |
There was a problem hiding this comment.
Please minimize the code inside the unsafe block to the minimum possible needed (i.e. the ffi call only)
Hi, in this code we just cast |
|
Since a pointer to |
|
@apoelstra Generics aren't trait objects. The monomorphisim will just replace that |
Do people have opinions on this? |
|
@real-or-random maybe it’s would lead to a slightly awkward API unless we change the C interface to stop taking a callback? With the current API, wouldn’t we have to pass in a dummy callback and then apply the user-provided rust function to the result of that? It’d work, but the code would look a bit odd perhaps? |
|
I think it leads to a less awkward API: Our user does not expect to provide a function I don't care that we internally provide a dummy callback. It may look odd but we have lots of odd code in this library. In fact, I think calling a dummy function would looks much less odd than the current suggestion in PR, and the long discussion about whether the current code is legal supports my point. |
You're right. idk how I missed that glaring thing. A note, our current API doesn't allow for failure. and honestly? hash functions should never fail. (well unless you pass the max limit allowed by some hash functions, even then if that limit is 64 bytes then it sucks) |
|
Too bad there are no const generics yet. |
Yeah, hm. If we want to support variable-length hash functions, then
Yes, a hash function should not fail. Maybe the more interesting question is if the user considers certain coordinate pairs invalid. But I don't think that's reasonable here. We promise to give a valid non-zero point to the callback (and there are no "weak" points / small subgroups whatever), so I agree: failures should not be allowed. |
|
@apoelstra might be able to respond to the current design choices for I see 3 reasonable options:
|
|
Can't we just genericize over |
|
Well we can keep But the question is how do we genericize the closure passed in. What should that return? Should we make the user create a SharedSecret? (don't think so) |
|
If we're fine passing in a dummy callback internally, then maybe having a |
|
If the author is fine with it I can try making an alternative for this that will try to keep idiomaticity (with some generic functions over SharedSecret) @shmishleniy |
|
I'm ok with any solution that will allow to get raw signature. Thanks for support. |
|
FWIW you can already unsafely do this using https://docs.rs/secp256k1/0.16.0/secp256k1/ffi/fn.secp256k1_ecdh.html (Not that I recommend doing it, as you can see there's a lot of hard safety questions here) |
|
Closing in favor of #180 |
#161 alternative