2014-08-12 02:26:14 +00:00
|
|
|
// Bitcoin secp256k1 bindings
|
|
|
|
// Written in 2014 by
|
|
|
|
// Dawid Ciężarkiewicz
|
|
|
|
// Andrew Poelstra
|
|
|
|
//
|
|
|
|
// To the extent possible under law, the author(s) have dedicated all
|
|
|
|
// copyright and related and neighboring rights to this software to
|
|
|
|
// the public domain worldwide. This software is distributed without
|
|
|
|
// any warranty.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the CC0 Public Domain Dedication
|
|
|
|
// along with this software.
|
|
|
|
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
|
|
|
//
|
2019-10-21 12:15:19 +00:00
|
|
|
//! # secp256k1-sys FFI bindings
|
2015-10-09 16:39:42 +00:00
|
|
|
//! Direct bindings to the underlying C library functions. These should
|
|
|
|
//! not be needed for most users.
|
2019-10-21 12:15:19 +00:00
|
|
|
|
2020-08-27 19:51:36 +00:00
|
|
|
// Coding conventions
|
2021-09-14 13:31:22 +00:00
|
|
|
#![deny(non_upper_case_globals, non_camel_case_types, non_snake_case, unused_mut)]
|
2019-10-21 12:15:19 +00:00
|
|
|
|
2020-08-27 19:51:36 +00:00
|
|
|
#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
|
2022-01-04 15:55:01 +00:00
|
|
|
#![cfg_attr(docsrs, feature(doc_cfg))]
|
|
|
|
|
2019-10-21 12:15:19 +00:00
|
|
|
#[cfg(any(test, feature = "std"))]
|
|
|
|
extern crate core;
|
|
|
|
|
2021-09-14 14:40:16 +00:00
|
|
|
#[cfg(feature = "alloc")]
|
|
|
|
extern crate alloc;
|
|
|
|
|
2021-01-11 19:14:42 +00:00
|
|
|
#[cfg(fuzzing)]
|
2020-12-22 17:34:50 +00:00
|
|
|
const THIS_UNUSED_CONSTANT_IS_YOUR_WARNING_THAT_ALL_THE_CRYPTO_IN_THIS_LIB_IS_DISABLED_FOR_FUZZING: usize = 0;
|
|
|
|
|
2019-10-21 12:15:19 +00:00
|
|
|
mod macros;
|
|
|
|
pub mod types;
|
|
|
|
|
|
|
|
#[cfg(feature = "recovery")]
|
2022-01-04 15:55:01 +00:00
|
|
|
#[cfg_attr(docsrs, doc(cfg(feature = "recovery")))]
|
2019-10-21 12:15:19 +00:00
|
|
|
pub mod recovery;
|
|
|
|
|
2021-11-04 14:48:08 +00:00
|
|
|
use core::{slice, ptr};
|
2022-12-01 04:22:24 +00:00
|
|
|
use core::ptr::NonNull;
|
2019-02-18 13:24:48 +00:00
|
|
|
use types::*;
|
2015-01-17 16:38:16 +00:00
|
|
|
|
2015-10-25 23:26:08 +00:00
|
|
|
/// Flag for context to enable no precomputation
|
2019-02-11 18:33:17 +00:00
|
|
|
pub const SECP256K1_START_NONE: c_uint = 1;
|
2015-09-20 17:52:46 +00:00
|
|
|
/// Flag for context to enable verification precomputation
|
2019-02-11 18:33:17 +00:00
|
|
|
pub const SECP256K1_START_VERIFY: c_uint = 1 | (1 << 8);
|
2015-09-20 17:52:46 +00:00
|
|
|
/// Flag for context to enable signing precomputation
|
2019-02-11 18:33:17 +00:00
|
|
|
pub const SECP256K1_START_SIGN: c_uint = 1 | (1 << 9);
|
2015-10-25 23:26:08 +00:00
|
|
|
/// Flag for keys to indicate uncompressed serialization format
|
2020-12-22 00:24:11 +00:00
|
|
|
#[allow(unused_parens)]
|
2019-02-11 18:33:17 +00:00
|
|
|
pub const SECP256K1_SER_UNCOMPRESSED: c_uint = (1 << 1);
|
2015-10-25 23:26:08 +00:00
|
|
|
/// Flag for keys to indicate compressed serialization format
|
|
|
|
pub const SECP256K1_SER_COMPRESSED: c_uint = (1 << 1) | (1 << 8);
|
2014-08-09 20:27:08 +00:00
|
|
|
|
2015-04-06 05:13:38 +00:00
|
|
|
/// A nonce generation function. Ordinary users of the library
|
|
|
|
/// never need to see this type; only if you need to control
|
|
|
|
/// nonce generation do you need to use it. I have deliberately
|
|
|
|
/// made this hard to do: you have to write your own wrapper
|
|
|
|
/// around the FFI functions to use it. And it's an unsafe type.
|
|
|
|
/// Nonces are generated deterministically by RFC6979 by
|
|
|
|
/// default; there should be no need to ever change this.
|
2020-12-22 21:17:31 +00:00
|
|
|
pub type NonceFn = Option<unsafe extern "C" fn(
|
|
|
|
nonce32: *mut c_uchar,
|
|
|
|
msg32: *const c_uchar,
|
|
|
|
key32: *const c_uchar,
|
|
|
|
algo16: *const c_uchar,
|
|
|
|
data: *mut c_void,
|
|
|
|
attempt: c_uint,
|
|
|
|
) -> c_int>;
|
2015-04-06 05:13:38 +00:00
|
|
|
|
2018-11-06 21:36:43 +00:00
|
|
|
/// Hash function to use to post-process an ECDH point to get
|
|
|
|
/// a shared secret.
|
2020-12-22 21:17:31 +00:00
|
|
|
pub type EcdhHashFn = Option<unsafe extern "C" fn(
|
2018-11-06 21:36:43 +00:00
|
|
|
output: *mut c_uchar,
|
|
|
|
x: *const c_uchar,
|
|
|
|
y: *const c_uchar,
|
2019-09-14 18:05:26 +00:00
|
|
|
data: *mut c_void,
|
2020-12-22 21:17:31 +00:00
|
|
|
) -> c_int>;
|
2015-04-11 17:00:20 +00:00
|
|
|
|
2020-09-15 01:42:20 +00:00
|
|
|
/// Same as secp256k1_nonce function with the exception of accepting an
|
|
|
|
/// additional pubkey argument and not requiring an attempt argument. The pubkey
|
|
|
|
/// argument can protect signature schemes with key-prefixed challenge hash
|
|
|
|
/// inputs against reusing the nonce when signing with the wrong precomputed
|
|
|
|
/// pubkey.
|
2020-12-22 21:17:31 +00:00
|
|
|
pub type SchnorrNonceFn = Option<unsafe extern "C" fn(
|
2020-09-15 01:42:20 +00:00
|
|
|
nonce32: *mut c_uchar,
|
|
|
|
msg32: *const c_uchar,
|
2022-05-06 03:16:53 +00:00
|
|
|
msg_len: size_t,
|
2020-09-15 01:42:20 +00:00
|
|
|
key32: *const c_uchar,
|
|
|
|
xonly_pk32: *const c_uchar,
|
|
|
|
algo16: *const c_uchar,
|
2022-05-06 03:16:53 +00:00
|
|
|
algo_len: size_t,
|
2020-09-15 01:42:20 +00:00
|
|
|
data: *mut c_void,
|
2020-12-22 21:17:31 +00:00
|
|
|
) -> c_int>;
|
2020-09-15 01:42:20 +00:00
|
|
|
|
2022-05-06 03:16:53 +00:00
|
|
|
/// Data structure that contains additional arguments for schnorrsig_sign_custom.
|
|
|
|
#[repr(C)]
|
|
|
|
pub struct SchnorrSigExtraParams {
|
|
|
|
magic: [c_uchar; 4],
|
|
|
|
nonce_fp: SchnorrNonceFn,
|
|
|
|
ndata: *const c_void,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SchnorrSigExtraParams {
|
|
|
|
/// Create a new SchnorrSigExtraParams properly initialized.
|
|
|
|
///
|
|
|
|
/// `nonce_fp`: pointer to a nonce generation function. If NULL
|
|
|
|
/// rustsecp256k1_v0_5_0_nonce_function_bip340 is used
|
|
|
|
///
|
|
|
|
/// `ndata`: pointer to arbitrary data used by the nonce generation function
|
|
|
|
/// (can be NULL). If it is non-NULL and
|
|
|
|
/// rustsecp256k1_v0_5_0_nonce_function_bip340 is used,
|
|
|
|
/// then ndata must be a pointer to 32-byte auxiliary randomness as per
|
|
|
|
/// BIP-340.
|
|
|
|
pub fn new(nonce_fp: SchnorrNonceFn, ndata: *const c_void) -> Self {
|
|
|
|
SchnorrSigExtraParams {
|
|
|
|
magic: [0xda, 0x6f, 0xb3, 0x8c],
|
|
|
|
nonce_fp,
|
|
|
|
ndata,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-11 17:00:20 +00:00
|
|
|
/// A Secp256k1 context, containing various precomputed values and such
|
|
|
|
/// needed to do elliptic curve computations. If you create one of these
|
|
|
|
/// with `secp256k1_context_create` you MUST destroy it with
|
|
|
|
/// `secp256k1_context_destroy`, or else you will have a memory leak.
|
2015-11-15 23:00:07 +00:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
#[repr(C)] pub struct Context(c_int);
|
2015-04-11 17:00:20 +00:00
|
|
|
|
2015-07-28 16:03:10 +00:00
|
|
|
/// Library-internal representation of a Secp256k1 public key
|
|
|
|
#[repr(C)]
|
2022-11-17 23:56:24 +00:00
|
|
|
#[derive(Copy, Clone)]
|
2015-07-28 16:03:10 +00:00
|
|
|
pub struct PublicKey([c_uchar; 64]);
|
|
|
|
impl_array_newtype!(PublicKey, c_uchar, 64);
|
|
|
|
impl_raw_debug!(PublicKey);
|
|
|
|
|
|
|
|
impl PublicKey {
|
2020-11-27 17:49:11 +00:00
|
|
|
/// Creates an "uninitialized" FFI public key which is zeroed out
|
|
|
|
///
|
2022-04-27 00:20:02 +00:00
|
|
|
/// # Safety
|
|
|
|
///
|
2020-11-27 17:49:11 +00:00
|
|
|
/// If you pass this to any FFI functions, except as an out-pointer,
|
|
|
|
/// the result is likely to be an assertation failure and process
|
|
|
|
/// termination.
|
|
|
|
pub unsafe fn new() -> Self {
|
|
|
|
Self::from_array_unchecked([0; 64])
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a new public key usable for the FFI interface from raw bytes
|
|
|
|
///
|
2022-04-27 00:20:02 +00:00
|
|
|
/// # Safety
|
|
|
|
///
|
2020-11-27 17:49:11 +00:00
|
|
|
/// Does not check the validity of the underlying representation. If it is
|
|
|
|
/// invalid the result may be assertation failures (and process aborts) from
|
|
|
|
/// the underlying library. You should not use this method except with data
|
|
|
|
/// that you obtained from the FFI interface of the same version of this
|
|
|
|
/// library.
|
|
|
|
pub unsafe fn from_array_unchecked(data: [c_uchar; 64]) -> Self {
|
|
|
|
PublicKey(data)
|
|
|
|
}
|
2015-07-28 16:03:10 +00:00
|
|
|
|
2020-11-27 17:49:11 +00:00
|
|
|
/// Returns the underlying FFI opaque representation of the public key
|
|
|
|
///
|
|
|
|
/// You should not use this unless you really know what you are doing. It is
|
|
|
|
/// essentially only useful for extending the FFI interface itself.
|
|
|
|
pub fn underlying_bytes(self) -> [c_uchar; 64] {
|
|
|
|
self.0
|
2019-02-11 18:33:17 +00:00
|
|
|
}
|
Implement stable comparison functionality
Currently we rely on the inner bytes with types that are passed across
the FFI boundry when implementing comparison functions (e.g. `Ord`,
`PartialEq`), this is incorrect because the bytes are opaque, meaning
the byte layout is not guaranteed across versions of `libsecp26k1`.
Implement stable comparison functionality by doing:
- Implement `core::cmp` traits by first coercing the data into a stable
form e.g., by serializing it.
- Add fast comparison methods to `secp256k1-sys` types that wrap types
from libsecp, add similar methods to types in `secp256k1` that wrap
`secp256k1-sys` types (just call through to inner type).
- In `secp256k1-sys` feature gate the new `core::cmp` impls on
`not(fuzzing)`, when fuzzing just derive the impls instead.
Any additional methods added to `secp256k1-sys` types are private,
justified by the fact the -sys is meant to be just a thin wrapper around
libsecp256k1, we don't want to commit to supporting additional API
functions.
Please note, the solution presented in this patch is already present for
`secp256k1::PublicKey`, this PR removes that code in favour of deriving
traits that then call down to the same logic in `secp256k1-sys`.
2022-11-17 04:56:35 +00:00
|
|
|
|
|
|
|
/// Serializes this public key as a byte-encoded pair of values, in compressed form.
|
|
|
|
fn serialize(&self) -> [u8; 33] {
|
|
|
|
let mut buf = [0u8; 33];
|
|
|
|
let mut len = 33;
|
|
|
|
unsafe {
|
|
|
|
let ret = secp256k1_ec_pubkey_serialize(
|
|
|
|
secp256k1_context_no_precomp,
|
|
|
|
buf.as_mut_c_ptr(),
|
|
|
|
&mut len,
|
|
|
|
self,
|
|
|
|
SECP256K1_SER_COMPRESSED,
|
|
|
|
);
|
|
|
|
debug_assert_eq!(ret, 1);
|
|
|
|
debug_assert_eq!(len, 33);
|
|
|
|
};
|
|
|
|
buf
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(fuzzing))]
|
|
|
|
impl PartialOrd for PublicKey {
|
|
|
|
fn partial_cmp(&self, other: &PublicKey) -> Option<core::cmp::Ordering> {
|
|
|
|
Some(self.cmp(other))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(fuzzing))]
|
|
|
|
impl Ord for PublicKey {
|
|
|
|
fn cmp(&self, other: &PublicKey) -> core::cmp::Ordering {
|
|
|
|
let ret = unsafe {
|
|
|
|
secp256k1_ec_pubkey_cmp(secp256k1_context_no_precomp, self, other)
|
|
|
|
};
|
|
|
|
ret.cmp(&0i32)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(fuzzing))]
|
|
|
|
impl PartialEq for PublicKey {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
self.cmp(other) == core::cmp::Ordering::Equal
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(fuzzing))]
|
|
|
|
impl Eq for PublicKey {}
|
|
|
|
|
|
|
|
#[cfg(not(fuzzing))]
|
|
|
|
impl core::hash::Hash for PublicKey {
|
|
|
|
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
|
|
|
let ser = self.serialize();
|
|
|
|
ser.hash(state);
|
|
|
|
}
|
2019-02-11 18:33:17 +00:00
|
|
|
}
|
|
|
|
|
2015-07-28 16:03:10 +00:00
|
|
|
/// Library-internal representation of a Secp256k1 signature
|
|
|
|
#[repr(C)]
|
2022-11-17 23:56:24 +00:00
|
|
|
#[derive(Copy, Clone)]
|
2015-09-18 20:22:48 +00:00
|
|
|
pub struct Signature([c_uchar; 64]);
|
|
|
|
impl_array_newtype!(Signature, c_uchar, 64);
|
2015-07-28 16:03:10 +00:00
|
|
|
impl_raw_debug!(Signature);
|
|
|
|
|
|
|
|
impl Signature {
|
2020-11-27 17:49:11 +00:00
|
|
|
/// Creates an "uninitialized" FFI signature which is zeroed out
|
|
|
|
///
|
2022-04-27 00:20:02 +00:00
|
|
|
/// # Safety
|
|
|
|
///
|
2020-11-27 17:49:11 +00:00
|
|
|
/// If you pass this to any FFI functions, except as an out-pointer,
|
|
|
|
/// the result is likely to be an assertation failure and process
|
|
|
|
/// termination.
|
|
|
|
pub unsafe fn new() -> Self {
|
|
|
|
Self::from_array_unchecked([0; 64])
|
|
|
|
}
|
2015-07-28 16:03:10 +00:00
|
|
|
|
2020-11-27 17:49:11 +00:00
|
|
|
/// Create a new signature usable for the FFI interface from raw bytes
|
|
|
|
///
|
2022-04-27 00:20:02 +00:00
|
|
|
/// # Safety
|
|
|
|
///
|
2020-11-27 17:49:11 +00:00
|
|
|
/// Does not check the validity of the underlying representation. If it is
|
|
|
|
/// invalid the result may be assertation failures (and process aborts) from
|
|
|
|
/// the underlying library. You should not use this method except with data
|
|
|
|
/// that you obtained from the FFI interface of the same version of this
|
|
|
|
/// library.
|
|
|
|
pub unsafe fn from_array_unchecked(data: [c_uchar; 64]) -> Self {
|
|
|
|
Signature(data)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the underlying FFI opaque representation of the signature
|
|
|
|
///
|
|
|
|
/// You should not use this unless you really know what you are doing. It is
|
|
|
|
/// essentially only useful for extending the FFI interface itself.
|
|
|
|
pub fn underlying_bytes(self) -> [c_uchar; 64] {
|
|
|
|
self.0
|
2019-02-11 18:33:17 +00:00
|
|
|
}
|
Implement stable comparison functionality
Currently we rely on the inner bytes with types that are passed across
the FFI boundry when implementing comparison functions (e.g. `Ord`,
`PartialEq`), this is incorrect because the bytes are opaque, meaning
the byte layout is not guaranteed across versions of `libsecp26k1`.
Implement stable comparison functionality by doing:
- Implement `core::cmp` traits by first coercing the data into a stable
form e.g., by serializing it.
- Add fast comparison methods to `secp256k1-sys` types that wrap types
from libsecp, add similar methods to types in `secp256k1` that wrap
`secp256k1-sys` types (just call through to inner type).
- In `secp256k1-sys` feature gate the new `core::cmp` impls on
`not(fuzzing)`, when fuzzing just derive the impls instead.
Any additional methods added to `secp256k1-sys` types are private,
justified by the fact the -sys is meant to be just a thin wrapper around
libsecp256k1, we don't want to commit to supporting additional API
functions.
Please note, the solution presented in this patch is already present for
`secp256k1::PublicKey`, this PR removes that code in favour of deriving
traits that then call down to the same logic in `secp256k1-sys`.
2022-11-17 04:56:35 +00:00
|
|
|
|
|
|
|
/// Serializes the signature in compact format.
|
|
|
|
fn serialize(&self) -> [u8; 64] {
|
|
|
|
let mut buf = [0u8; 64];
|
|
|
|
unsafe {
|
|
|
|
let ret = secp256k1_ecdsa_signature_serialize_compact(
|
|
|
|
secp256k1_context_no_precomp,
|
|
|
|
buf.as_mut_c_ptr(),
|
|
|
|
self,
|
|
|
|
);
|
|
|
|
debug_assert!(ret == 1);
|
|
|
|
}
|
|
|
|
buf
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(fuzzing))]
|
|
|
|
impl PartialOrd for Signature {
|
|
|
|
fn partial_cmp(&self, other: &Signature) -> Option<core::cmp::Ordering> {
|
|
|
|
Some(self.cmp(other))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(fuzzing))]
|
|
|
|
impl Ord for Signature {
|
|
|
|
fn cmp(&self, other: &Signature) -> core::cmp::Ordering {
|
|
|
|
let this = self.serialize();
|
|
|
|
let that = other.serialize();
|
|
|
|
this.cmp(&that)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(fuzzing))]
|
|
|
|
impl PartialEq for Signature {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
self.cmp(other) == core::cmp::Ordering::Equal
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(fuzzing))]
|
|
|
|
impl Eq for Signature {}
|
|
|
|
|
|
|
|
#[cfg(not(fuzzing))]
|
|
|
|
impl core::hash::Hash for Signature {
|
|
|
|
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
|
|
|
let ser = self.serialize();
|
|
|
|
ser.hash(state);
|
|
|
|
}
|
2019-02-11 18:33:17 +00:00
|
|
|
}
|
|
|
|
|
2020-09-15 01:42:20 +00:00
|
|
|
#[repr(C)]
|
2022-11-17 23:56:24 +00:00
|
|
|
#[derive(Copy, Clone)]
|
2020-09-15 01:42:20 +00:00
|
|
|
pub struct XOnlyPublicKey([c_uchar; 64]);
|
|
|
|
impl_array_newtype!(XOnlyPublicKey, c_uchar, 64);
|
|
|
|
impl_raw_debug!(XOnlyPublicKey);
|
|
|
|
|
|
|
|
impl XOnlyPublicKey {
|
2020-11-27 17:49:11 +00:00
|
|
|
/// Creates an "uninitialized" FFI x-only public key which is zeroed out
|
|
|
|
///
|
2022-04-27 00:20:02 +00:00
|
|
|
/// # Safety
|
|
|
|
///
|
2020-11-27 17:49:11 +00:00
|
|
|
/// If you pass this to any FFI functions, except as an out-pointer,
|
|
|
|
/// the result is likely to be an assertation failure and process
|
|
|
|
/// termination.
|
|
|
|
pub unsafe fn new() -> Self {
|
|
|
|
Self::from_array_unchecked([0; 64])
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a new x-only public key usable for the FFI interface from raw bytes
|
|
|
|
///
|
2022-04-27 00:20:02 +00:00
|
|
|
/// # Safety
|
|
|
|
///
|
2020-11-27 17:49:11 +00:00
|
|
|
/// Does not check the validity of the underlying representation. If it is
|
|
|
|
/// invalid the result may be assertation failures (and process aborts) from
|
|
|
|
/// the underlying library. You should not use this method except with data
|
|
|
|
/// that you obtained from the FFI interface of the same version of this
|
|
|
|
/// library.
|
|
|
|
pub unsafe fn from_array_unchecked(data: [c_uchar; 64]) -> Self {
|
2020-09-15 01:42:20 +00:00
|
|
|
XOnlyPublicKey(data)
|
|
|
|
}
|
2020-11-27 17:49:11 +00:00
|
|
|
|
|
|
|
/// Returns the underlying FFI opaque representation of the x-only public key
|
|
|
|
///
|
|
|
|
/// You should not use this unless you really know what you are doing. It is
|
|
|
|
/// essentially only useful for extending the FFI interface itself.
|
|
|
|
pub fn underlying_bytes(self) -> [c_uchar; 64] {
|
|
|
|
self.0
|
|
|
|
}
|
Implement stable comparison functionality
Currently we rely on the inner bytes with types that are passed across
the FFI boundry when implementing comparison functions (e.g. `Ord`,
`PartialEq`), this is incorrect because the bytes are opaque, meaning
the byte layout is not guaranteed across versions of `libsecp26k1`.
Implement stable comparison functionality by doing:
- Implement `core::cmp` traits by first coercing the data into a stable
form e.g., by serializing it.
- Add fast comparison methods to `secp256k1-sys` types that wrap types
from libsecp, add similar methods to types in `secp256k1` that wrap
`secp256k1-sys` types (just call through to inner type).
- In `secp256k1-sys` feature gate the new `core::cmp` impls on
`not(fuzzing)`, when fuzzing just derive the impls instead.
Any additional methods added to `secp256k1-sys` types are private,
justified by the fact the -sys is meant to be just a thin wrapper around
libsecp256k1, we don't want to commit to supporting additional API
functions.
Please note, the solution presented in this patch is already present for
`secp256k1::PublicKey`, this PR removes that code in favour of deriving
traits that then call down to the same logic in `secp256k1-sys`.
2022-11-17 04:56:35 +00:00
|
|
|
|
|
|
|
/// Serializes this key as a byte-encoded x coordinate value (32 bytes).
|
|
|
|
fn serialize(&self) -> [u8; 32] {
|
|
|
|
let mut buf = [0u8; 32];
|
|
|
|
unsafe {
|
|
|
|
let ret = secp256k1_xonly_pubkey_serialize(
|
|
|
|
secp256k1_context_no_precomp,
|
|
|
|
buf.as_mut_c_ptr(),
|
|
|
|
self,
|
|
|
|
);
|
|
|
|
assert_eq!(ret, 1);
|
|
|
|
};
|
|
|
|
buf
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(fuzzing))]
|
|
|
|
impl PartialOrd for XOnlyPublicKey {
|
|
|
|
fn partial_cmp(&self, other: &XOnlyPublicKey) -> Option<core::cmp::Ordering> {
|
|
|
|
Some(self.cmp(other))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(fuzzing))]
|
|
|
|
impl Ord for XOnlyPublicKey {
|
|
|
|
fn cmp(&self, other: &XOnlyPublicKey) -> core::cmp::Ordering {
|
|
|
|
let ret = unsafe {
|
|
|
|
secp256k1_xonly_pubkey_cmp(secp256k1_context_no_precomp, self, other)
|
|
|
|
};
|
|
|
|
ret.cmp(&0i32)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(fuzzing))]
|
|
|
|
impl PartialEq for XOnlyPublicKey {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
self.cmp(other) == core::cmp::Ordering::Equal
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(fuzzing))]
|
|
|
|
impl Eq for XOnlyPublicKey {}
|
|
|
|
|
|
|
|
#[cfg(not(fuzzing))]
|
|
|
|
impl core::hash::Hash for XOnlyPublicKey {
|
|
|
|
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
|
|
|
let ser = self.serialize();
|
|
|
|
ser.hash(state);
|
|
|
|
}
|
2020-09-15 01:42:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[repr(C)]
|
2022-11-17 23:56:24 +00:00
|
|
|
#[derive(Copy, Clone)]
|
2020-09-15 01:42:20 +00:00
|
|
|
pub struct KeyPair([c_uchar; 96]);
|
|
|
|
impl_array_newtype!(KeyPair, c_uchar, 96);
|
|
|
|
impl_raw_debug!(KeyPair);
|
|
|
|
|
|
|
|
impl KeyPair {
|
2020-11-27 17:49:11 +00:00
|
|
|
/// Creates an "uninitialized" FFI keypair which is zeroed out
|
|
|
|
///
|
2022-04-27 00:20:02 +00:00
|
|
|
/// # Safety
|
|
|
|
///
|
2020-11-27 17:49:11 +00:00
|
|
|
/// If you pass this to any FFI functions, except as an out-pointer,
|
|
|
|
/// the result is likely to be an assertation failure and process
|
|
|
|
/// termination.
|
|
|
|
pub unsafe fn new() -> Self {
|
|
|
|
Self::from_array_unchecked([0; 96])
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a new keypair usable for the FFI interface from raw bytes
|
|
|
|
///
|
2022-04-27 00:20:02 +00:00
|
|
|
/// # Safety
|
|
|
|
///
|
2020-11-27 17:49:11 +00:00
|
|
|
/// Does not check the validity of the underlying representation. If it is
|
|
|
|
/// invalid the result may be assertation failures (and process aborts) from
|
|
|
|
/// the underlying library. You should not use this method except with data
|
|
|
|
/// that you obtained from the FFI interface of the same version of this
|
|
|
|
/// library.
|
|
|
|
pub unsafe fn from_array_unchecked(data: [c_uchar; 96]) -> Self {
|
2020-09-15 01:42:20 +00:00
|
|
|
KeyPair(data)
|
|
|
|
}
|
2020-11-27 17:49:11 +00:00
|
|
|
|
|
|
|
/// Returns the underlying FFI opaque representation of the x-only public key
|
|
|
|
///
|
|
|
|
/// You should not use this unless you really know what you are doing. It is
|
|
|
|
/// essentially only useful for extending the FFI interface itself.
|
|
|
|
pub fn underlying_bytes(self) -> [c_uchar; 96] {
|
|
|
|
self.0
|
|
|
|
}
|
Implement stable comparison functionality
Currently we rely on the inner bytes with types that are passed across
the FFI boundry when implementing comparison functions (e.g. `Ord`,
`PartialEq`), this is incorrect because the bytes are opaque, meaning
the byte layout is not guaranteed across versions of `libsecp26k1`.
Implement stable comparison functionality by doing:
- Implement `core::cmp` traits by first coercing the data into a stable
form e.g., by serializing it.
- Add fast comparison methods to `secp256k1-sys` types that wrap types
from libsecp, add similar methods to types in `secp256k1` that wrap
`secp256k1-sys` types (just call through to inner type).
- In `secp256k1-sys` feature gate the new `core::cmp` impls on
`not(fuzzing)`, when fuzzing just derive the impls instead.
Any additional methods added to `secp256k1-sys` types are private,
justified by the fact the -sys is meant to be just a thin wrapper around
libsecp256k1, we don't want to commit to supporting additional API
functions.
Please note, the solution presented in this patch is already present for
`secp256k1::PublicKey`, this PR removes that code in favour of deriving
traits that then call down to the same logic in `secp256k1-sys`.
2022-11-17 04:56:35 +00:00
|
|
|
|
|
|
|
/// Creates a new compressed public key from this key pair.
|
|
|
|
fn public_key(&self) -> PublicKey {
|
|
|
|
unsafe {
|
|
|
|
let mut pk = PublicKey::new();
|
|
|
|
let ret = secp256k1_keypair_pub(
|
|
|
|
secp256k1_context_no_precomp,
|
|
|
|
&mut pk,
|
|
|
|
self,
|
|
|
|
);
|
|
|
|
debug_assert_eq!(ret, 1);
|
|
|
|
pk
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(fuzzing))]
|
|
|
|
impl PartialOrd for KeyPair {
|
|
|
|
fn partial_cmp(&self, other: &KeyPair) -> Option<core::cmp::Ordering> {
|
|
|
|
Some(self.cmp(other))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(fuzzing))]
|
|
|
|
impl Ord for KeyPair {
|
|
|
|
fn cmp(&self, other: &KeyPair) -> core::cmp::Ordering {
|
|
|
|
let this = self.public_key();
|
|
|
|
let that = other.public_key();
|
|
|
|
this.cmp(&that)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(fuzzing))]
|
|
|
|
impl PartialEq for KeyPair {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
self.cmp(other) == core::cmp::Ordering::Equal
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(fuzzing))]
|
|
|
|
impl Eq for KeyPair {}
|
|
|
|
|
|
|
|
#[cfg(not(fuzzing))]
|
|
|
|
impl core::hash::Hash for KeyPair {
|
|
|
|
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
|
|
|
// To hash the key pair we just hash the serialized public key. Since any change to the
|
|
|
|
// secret key would also be a change to the public key this is a valid one way function from
|
|
|
|
// the key pair to the digest.
|
|
|
|
let pk = self.public_key();
|
|
|
|
let ser = pk.serialize();
|
|
|
|
ser.hash(state);
|
|
|
|
}
|
2020-09-15 01:42:20 +00:00
|
|
|
}
|
|
|
|
|
2014-08-09 20:27:08 +00:00
|
|
|
extern "C" {
|
2018-11-06 21:36:43 +00:00
|
|
|
/// Default ECDH hash function
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ecdh_hash_function_default")]
|
2018-11-06 21:36:43 +00:00
|
|
|
pub static secp256k1_ecdh_hash_function_default: EcdhHashFn;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_nonce_function_rfc6979")]
|
2015-04-06 05:13:38 +00:00
|
|
|
pub static secp256k1_nonce_function_rfc6979: NonceFn;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_nonce_function_default")]
|
2015-04-06 05:13:38 +00:00
|
|
|
pub static secp256k1_nonce_function_default: NonceFn;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_nonce_function_bip340")]
|
2020-12-22 20:16:10 +00:00
|
|
|
pub static secp256k1_nonce_function_bip340: SchnorrNonceFn;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_context_no_precomp")]
|
2018-11-06 21:57:52 +00:00
|
|
|
pub static secp256k1_context_no_precomp: *const Context;
|
|
|
|
|
2015-07-28 16:03:10 +00:00
|
|
|
// Contexts
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_context_preallocated_destroy")]
|
2022-12-01 04:22:24 +00:00
|
|
|
pub fn secp256k1_context_preallocated_destroy(cx: NonNull<Context>);
|
2019-05-28 17:48:26 +00:00
|
|
|
|
2015-07-28 16:03:10 +00:00
|
|
|
// Signatures
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ecdsa_signature_parse_der")]
|
2015-11-15 23:00:07 +00:00
|
|
|
pub fn secp256k1_ecdsa_signature_parse_der(cx: *const Context, sig: *mut Signature,
|
2020-04-29 19:13:22 +00:00
|
|
|
input: *const c_uchar, in_len: size_t)
|
2015-07-28 16:03:10 +00:00
|
|
|
-> c_int;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ecdsa_signature_parse_compact")]
|
2017-07-12 19:55:06 +00:00
|
|
|
pub fn secp256k1_ecdsa_signature_parse_compact(cx: *const Context, sig: *mut Signature,
|
|
|
|
input64: *const c_uchar)
|
|
|
|
-> c_int;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ecdsa_signature_parse_der_lax")]
|
2016-01-14 18:35:54 +00:00
|
|
|
pub fn ecdsa_signature_parse_der_lax(cx: *const Context, sig: *mut Signature,
|
2020-04-29 19:13:22 +00:00
|
|
|
input: *const c_uchar, in_len: size_t)
|
2016-01-14 18:35:54 +00:00
|
|
|
-> c_int;
|
2015-10-26 17:59:40 +00:00
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ecdsa_signature_serialize_der")]
|
2018-03-19 19:45:13 +00:00
|
|
|
pub fn secp256k1_ecdsa_signature_serialize_der(cx: *const Context, output: *mut c_uchar,
|
2020-04-29 19:13:22 +00:00
|
|
|
out_len: *mut size_t, sig: *const Signature)
|
2015-07-28 16:03:10 +00:00
|
|
|
-> c_int;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ecdsa_signature_serialize_compact")]
|
2019-09-14 18:05:26 +00:00
|
|
|
pub fn secp256k1_ecdsa_signature_serialize_compact(cx: *const Context, output64: *mut c_uchar,
|
2017-07-12 19:55:06 +00:00
|
|
|
sig: *const Signature)
|
|
|
|
-> c_int;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ecdsa_signature_normalize")]
|
2015-11-15 23:00:07 +00:00
|
|
|
pub fn secp256k1_ecdsa_signature_normalize(cx: *const Context, out_sig: *mut Signature,
|
2015-10-26 19:25:18 +00:00
|
|
|
in_sig: *const Signature)
|
|
|
|
-> c_int;
|
|
|
|
|
2021-02-18 14:55:46 +00:00
|
|
|
// Secret Keys
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ec_seckey_verify")]
|
2015-11-15 23:00:07 +00:00
|
|
|
pub fn secp256k1_ec_seckey_verify(cx: *const Context,
|
2015-04-11 17:00:20 +00:00
|
|
|
sk: *const c_uchar) -> c_int;
|
2014-08-28 16:16:53 +00:00
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ec_seckey_negate")]
|
2020-05-13 11:50:57 +00:00
|
|
|
pub fn secp256k1_ec_seckey_negate(cx: *const Context,
|
|
|
|
sk: *mut c_uchar) -> c_int;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ec_seckey_tweak_add")]
|
2020-05-13 11:50:57 +00:00
|
|
|
pub fn secp256k1_ec_seckey_tweak_add(cx: *const Context,
|
|
|
|
sk: *mut c_uchar,
|
|
|
|
tweak: *const c_uchar)
|
|
|
|
-> c_int;
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ec_seckey_tweak_mul")]
|
2020-05-13 11:50:57 +00:00
|
|
|
pub fn secp256k1_ec_seckey_tweak_mul(cx: *const Context,
|
|
|
|
sk: *mut c_uchar,
|
|
|
|
tweak: *const c_uchar)
|
|
|
|
-> c_int;
|
2021-06-18 21:33:37 +00:00
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_keypair_sec")]
|
2021-06-18 21:33:37 +00:00
|
|
|
pub fn secp256k1_keypair_sec(cx: *const Context,
|
|
|
|
output_seckey: *mut c_uchar,
|
|
|
|
keypair: *const KeyPair)
|
|
|
|
-> c_int;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_keypair_pub")]
|
2021-06-18 21:33:37 +00:00
|
|
|
pub fn secp256k1_keypair_pub(cx: *const Context,
|
|
|
|
output_pubkey: *mut PublicKey,
|
|
|
|
keypair: *const KeyPair)
|
|
|
|
-> c_int;
|
2021-02-18 14:55:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(fuzzing))]
|
|
|
|
extern "C" {
|
|
|
|
// Contexts
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_context_preallocated_size")]
|
2021-02-18 14:55:46 +00:00
|
|
|
pub fn secp256k1_context_preallocated_size(flags: c_uint) -> size_t;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_context_preallocated_create")]
|
2022-12-01 04:22:24 +00:00
|
|
|
pub fn secp256k1_context_preallocated_create(prealloc: NonNull<c_void>, flags: c_uint) -> NonNull<Context>;
|
2021-02-18 14:55:46 +00:00
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_context_preallocated_clone_size")]
|
2021-02-18 14:55:46 +00:00
|
|
|
pub fn secp256k1_context_preallocated_clone_size(cx: *const Context) -> size_t;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_context_preallocated_clone")]
|
2022-12-01 04:22:24 +00:00
|
|
|
pub fn secp256k1_context_preallocated_clone(cx: *const Context, prealloc: NonNull<c_void>) -> NonNull<Context>;
|
2021-02-18 14:55:46 +00:00
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_context_randomize")]
|
2022-12-01 04:22:24 +00:00
|
|
|
pub fn secp256k1_context_randomize(cx: NonNull<Context>,
|
2021-02-27 04:20:48 +00:00
|
|
|
seed32: *const c_uchar)
|
|
|
|
-> c_int;
|
2021-02-18 14:55:46 +00:00
|
|
|
// Pubkeys
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ec_pubkey_parse")]
|
2021-02-18 14:55:46 +00:00
|
|
|
pub fn secp256k1_ec_pubkey_parse(cx: *const Context, pk: *mut PublicKey,
|
|
|
|
input: *const c_uchar, in_len: size_t)
|
|
|
|
-> c_int;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ec_pubkey_serialize")]
|
2021-02-18 14:55:46 +00:00
|
|
|
pub fn secp256k1_ec_pubkey_serialize(cx: *const Context, output: *mut c_uchar,
|
|
|
|
out_len: *mut size_t, pk: *const PublicKey,
|
|
|
|
compressed: c_uint)
|
|
|
|
-> c_int;
|
2020-05-13 11:50:57 +00:00
|
|
|
|
2020-12-22 20:16:10 +00:00
|
|
|
// EC
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ec_pubkey_create")]
|
2020-12-22 20:16:10 +00:00
|
|
|
pub fn secp256k1_ec_pubkey_create(cx: *const Context, pk: *mut PublicKey,
|
|
|
|
sk: *const c_uchar) -> c_int;
|
|
|
|
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ec_pubkey_negate")]
|
2020-12-22 20:16:10 +00:00
|
|
|
pub fn secp256k1_ec_pubkey_negate(cx: *const Context,
|
|
|
|
pk: *mut PublicKey) -> c_int;
|
|
|
|
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ec_pubkey_cmp")]
|
2021-06-29 11:19:18 +00:00
|
|
|
pub fn secp256k1_ec_pubkey_cmp(cx: *const Context,
|
|
|
|
pubkey1: *const PublicKey,
|
|
|
|
pubkey2: *const PublicKey)
|
|
|
|
-> c_int;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ec_pubkey_tweak_add")]
|
2020-12-22 20:16:10 +00:00
|
|
|
pub fn secp256k1_ec_pubkey_tweak_add(cx: *const Context,
|
|
|
|
pk: *mut PublicKey,
|
|
|
|
tweak: *const c_uchar)
|
|
|
|
-> c_int;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ec_pubkey_tweak_mul")]
|
2015-11-15 23:00:07 +00:00
|
|
|
pub fn secp256k1_ec_pubkey_tweak_mul(cx: *const Context,
|
2015-07-28 16:03:10 +00:00
|
|
|
pk: *mut PublicKey,
|
2015-01-17 16:38:16 +00:00
|
|
|
tweak: *const c_uchar)
|
|
|
|
-> c_int;
|
2015-05-03 23:22:30 +00:00
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ec_pubkey_combine")]
|
2015-11-15 23:00:07 +00:00
|
|
|
pub fn secp256k1_ec_pubkey_combine(cx: *const Context,
|
2015-07-28 16:03:10 +00:00
|
|
|
out: *mut PublicKey,
|
2015-09-18 20:22:48 +00:00
|
|
|
ins: *const *const PublicKey,
|
|
|
|
n: c_int)
|
2015-05-03 23:22:30 +00:00
|
|
|
-> c_int;
|
2015-09-18 20:22:48 +00:00
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ecdh")]
|
2018-11-06 21:36:43 +00:00
|
|
|
pub fn secp256k1_ecdh(
|
|
|
|
cx: *const Context,
|
2019-11-09 22:02:44 +00:00
|
|
|
output: *mut c_uchar,
|
2018-11-06 21:36:43 +00:00
|
|
|
pubkey: *const PublicKey,
|
2020-05-13 11:50:57 +00:00
|
|
|
seckey: *const c_uchar,
|
2018-11-06 21:36:43 +00:00
|
|
|
hashfp: EcdhHashFn,
|
|
|
|
data: *mut c_void,
|
|
|
|
) -> c_int;
|
2020-09-15 01:42:20 +00:00
|
|
|
|
2021-02-18 14:55:46 +00:00
|
|
|
// ECDSA
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ecdsa_verify")]
|
2021-02-18 14:55:46 +00:00
|
|
|
pub fn secp256k1_ecdsa_verify(cx: *const Context,
|
|
|
|
sig: *const Signature,
|
|
|
|
msg32: *const c_uchar,
|
|
|
|
pk: *const PublicKey)
|
|
|
|
-> c_int;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_ecdsa_sign")]
|
2021-02-18 14:55:46 +00:00
|
|
|
pub fn secp256k1_ecdsa_sign(cx: *const Context,
|
|
|
|
sig: *mut Signature,
|
|
|
|
msg32: *const c_uchar,
|
|
|
|
sk: *const c_uchar,
|
|
|
|
noncefn: NonceFn,
|
|
|
|
noncedata: *const c_void)
|
|
|
|
-> c_int;
|
|
|
|
|
|
|
|
// Schnorr Signatures
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_schnorrsig_sign")]
|
2021-02-18 14:55:46 +00:00
|
|
|
pub fn secp256k1_schnorrsig_sign(
|
|
|
|
cx: *const Context,
|
|
|
|
sig: *mut c_uchar,
|
|
|
|
msg32: *const c_uchar,
|
|
|
|
keypair: *const KeyPair,
|
2022-03-08 19:45:41 +00:00
|
|
|
aux_rand32: *const c_uchar
|
2021-02-18 14:55:46 +00:00
|
|
|
) -> c_int;
|
|
|
|
|
2022-05-06 03:16:53 +00:00
|
|
|
// Schnorr Signatures with extra parameters (see [`SchnorrSigExtraParams`])
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_schnorrsig_sign_custom")]
|
2022-05-06 03:16:53 +00:00
|
|
|
pub fn secp256k1_schnorrsig_sign_custom(
|
|
|
|
cx: *const Context,
|
|
|
|
sig: *mut c_uchar,
|
|
|
|
msg: *const c_uchar,
|
|
|
|
msg_len: size_t,
|
|
|
|
keypair: *const KeyPair,
|
|
|
|
extra_params: *const SchnorrSigExtraParams,
|
|
|
|
) -> c_int;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_schnorrsig_verify")]
|
2021-02-18 14:55:46 +00:00
|
|
|
pub fn secp256k1_schnorrsig_verify(
|
|
|
|
cx: *const Context,
|
|
|
|
sig64: *const c_uchar,
|
|
|
|
msg32: *const c_uchar,
|
2022-03-08 19:45:41 +00:00
|
|
|
msglen: size_t,
|
2021-02-18 14:55:46 +00:00
|
|
|
pubkey: *const XOnlyPublicKey,
|
|
|
|
) -> c_int;
|
|
|
|
|
2020-09-15 01:42:20 +00:00
|
|
|
// Extra keys
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_keypair_create")]
|
2020-09-15 01:42:20 +00:00
|
|
|
pub fn secp256k1_keypair_create(
|
|
|
|
cx: *const Context,
|
|
|
|
keypair: *mut KeyPair,
|
|
|
|
seckey: *const c_uchar,
|
|
|
|
) -> c_int;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_xonly_pubkey_parse")]
|
2020-09-15 01:42:20 +00:00
|
|
|
pub fn secp256k1_xonly_pubkey_parse(
|
|
|
|
cx: *const Context,
|
|
|
|
pubkey: *mut XOnlyPublicKey,
|
|
|
|
input32: *const c_uchar,
|
|
|
|
) -> c_int;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_xonly_pubkey_serialize")]
|
2020-09-15 01:42:20 +00:00
|
|
|
pub fn secp256k1_xonly_pubkey_serialize(
|
|
|
|
cx: *const Context,
|
|
|
|
output32: *mut c_uchar,
|
|
|
|
pubkey: *const XOnlyPublicKey,
|
|
|
|
) -> c_int;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_xonly_pubkey_from_pubkey")]
|
2020-09-15 01:42:20 +00:00
|
|
|
pub fn secp256k1_xonly_pubkey_from_pubkey(
|
|
|
|
cx: *const Context,
|
|
|
|
xonly_pubkey: *mut XOnlyPublicKey,
|
|
|
|
pk_parity: *mut c_int,
|
|
|
|
pubkey: *const PublicKey,
|
|
|
|
) -> c_int;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_xonly_pubkey_cmp")]
|
2021-06-29 11:19:18 +00:00
|
|
|
pub fn secp256k1_xonly_pubkey_cmp(
|
|
|
|
cx: *const Context,
|
|
|
|
pubkey1: *const XOnlyPublicKey,
|
|
|
|
pubkey2: *const XOnlyPublicKey
|
|
|
|
) -> c_int;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_xonly_pubkey_tweak_add")]
|
2020-09-15 01:42:20 +00:00
|
|
|
pub fn secp256k1_xonly_pubkey_tweak_add(
|
|
|
|
cx: *const Context,
|
|
|
|
output_pubkey: *mut PublicKey,
|
|
|
|
internal_pubkey: *const XOnlyPublicKey,
|
|
|
|
tweak32: *const c_uchar,
|
|
|
|
) -> c_int;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_keypair_xonly_pub")]
|
2020-09-15 01:42:20 +00:00
|
|
|
pub fn secp256k1_keypair_xonly_pub(
|
|
|
|
cx: *const Context,
|
|
|
|
pubkey: *mut XOnlyPublicKey,
|
|
|
|
pk_parity: *mut c_int,
|
|
|
|
keypair: *const KeyPair
|
|
|
|
) -> c_int;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_keypair_xonly_tweak_add")]
|
2020-09-15 01:42:20 +00:00
|
|
|
pub fn secp256k1_keypair_xonly_tweak_add(
|
|
|
|
cx: *const Context,
|
|
|
|
keypair: *mut KeyPair,
|
|
|
|
tweak32: *const c_uchar,
|
|
|
|
) -> c_int;
|
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_8_0_xonly_pubkey_tweak_add_check")]
|
2020-09-15 01:42:20 +00:00
|
|
|
pub fn secp256k1_xonly_pubkey_tweak_add_check(
|
|
|
|
cx: *const Context,
|
|
|
|
tweaked_pubkey32: *const c_uchar,
|
|
|
|
tweaked_pubkey_parity: c_int,
|
|
|
|
internal_pubkey: *const XOnlyPublicKey,
|
|
|
|
tweak32: *const c_uchar,
|
|
|
|
) -> c_int;
|
2014-08-09 20:27:08 +00:00
|
|
|
}
|
|
|
|
|
2019-07-13 04:08:53 +00:00
|
|
|
/// A reimplementation of the C function `secp256k1_context_create` in rust.
|
|
|
|
///
|
2022-04-27 00:22:08 +00:00
|
|
|
/// This function allocates memory, the pointer should be deallocated using
|
|
|
|
/// `secp256k1_context_destroy`. Failure to do so will result in a memory leak.
|
2019-07-13 04:08:53 +00:00
|
|
|
///
|
2022-04-27 00:22:08 +00:00
|
|
|
/// Input `flags` control which parts of the context to initialize.
|
|
|
|
///
|
2022-11-21 20:49:16 +00:00
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// This function is unsafe because it calls unsafe functions however (assuming no bugs) no
|
|
|
|
/// undefined behavior is possible.
|
|
|
|
///
|
2022-04-27 00:22:08 +00:00
|
|
|
/// # Returns
|
|
|
|
///
|
|
|
|
/// The newly created secp256k1 raw context.
|
2022-11-21 20:49:16 +00:00
|
|
|
#[cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))]
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))))]
|
2022-12-01 04:22:24 +00:00
|
|
|
pub unsafe fn secp256k1_context_create(flags: c_uint) -> NonNull<Context> {
|
2022-12-20 21:11:14 +00:00
|
|
|
rustsecp256k1_v0_8_0_context_create(flags)
|
2022-11-21 20:49:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// A reimplementation of the C function `secp256k1_context_create` in rust.
|
|
|
|
///
|
|
|
|
/// See [`secp256k1_context_create`] for documentation and safety constraints.
|
2019-10-29 11:19:53 +00:00
|
|
|
#[no_mangle]
|
2022-11-21 20:49:16 +00:00
|
|
|
#[allow(clippy::missing_safety_doc)] // Documented above.
|
2021-09-14 14:40:16 +00:00
|
|
|
#[cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))]
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))))]
|
2022-12-20 21:11:14 +00:00
|
|
|
pub unsafe extern "C" fn rustsecp256k1_v0_8_0_context_create(flags: c_uint) -> NonNull<Context> {
|
2020-08-28 10:58:07 +00:00
|
|
|
use core::mem;
|
2021-09-14 14:40:16 +00:00
|
|
|
use crate::alloc::alloc;
|
2020-08-28 10:58:07 +00:00
|
|
|
assert!(ALIGN_TO >= mem::align_of::<usize>());
|
|
|
|
assert!(ALIGN_TO >= mem::align_of::<&usize>());
|
|
|
|
assert!(ALIGN_TO >= mem::size_of::<usize>());
|
|
|
|
|
|
|
|
// We need to allocate `ALIGN_TO` more bytes in order to write the amount of bytes back.
|
|
|
|
let bytes = secp256k1_context_preallocated_size(flags) + ALIGN_TO;
|
|
|
|
let layout = alloc::Layout::from_size_align(bytes, ALIGN_TO).unwrap();
|
|
|
|
let ptr = alloc::alloc(layout);
|
2022-11-24 11:14:23 +00:00
|
|
|
if ptr.is_null() {
|
|
|
|
alloc::handle_alloc_error(layout);
|
|
|
|
}
|
2020-08-28 10:58:07 +00:00
|
|
|
(ptr as *mut usize).write(bytes);
|
|
|
|
// We must offset a whole ALIGN_TO in order to preserve the same alignment
|
|
|
|
// this means we "lose" ALIGN_TO-size_of(usize) for padding.
|
2022-12-01 04:22:24 +00:00
|
|
|
let ptr = ptr.add(ALIGN_TO);
|
|
|
|
let ptr = NonNull::new_unchecked(ptr as *mut c_void); // Checked above.
|
2020-08-28 10:58:07 +00:00
|
|
|
secp256k1_context_preallocated_create(ptr, flags)
|
2019-07-13 04:08:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// A reimplementation of the C function `secp256k1_context_destroy` in rust.
|
|
|
|
///
|
|
|
|
/// This function destroys and deallcates the context created by `secp256k1_context_create`.
|
|
|
|
///
|
|
|
|
/// The pointer shouldn't be used after passing to this function, consider it as passing it to `free()`.
|
|
|
|
///
|
2022-11-21 20:49:16 +00:00
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// `ctx` must be a valid pointer to a block of memory created using [`secp256k1_context_create`].
|
|
|
|
#[cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))]
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))))]
|
2022-12-01 04:22:24 +00:00
|
|
|
pub unsafe fn secp256k1_context_destroy(ctx: NonNull<Context>) {
|
2022-12-20 21:11:14 +00:00
|
|
|
rustsecp256k1_v0_8_0_context_destroy(ctx)
|
2022-11-21 20:49:16 +00:00
|
|
|
}
|
|
|
|
|
2019-10-29 11:19:53 +00:00
|
|
|
#[no_mangle]
|
2022-11-21 20:49:16 +00:00
|
|
|
#[allow(clippy::missing_safety_doc)] // Documented above.
|
2021-09-14 14:40:16 +00:00
|
|
|
#[cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))]
|
|
|
|
#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))))]
|
2022-12-20 21:11:14 +00:00
|
|
|
pub unsafe extern "C" fn rustsecp256k1_v0_8_0_context_destroy(mut ctx: NonNull<Context>) {
|
2021-09-14 14:40:16 +00:00
|
|
|
use crate::alloc::alloc;
|
2019-07-13 04:08:53 +00:00
|
|
|
secp256k1_context_preallocated_destroy(ctx);
|
2022-12-01 04:22:24 +00:00
|
|
|
let ctx: *mut Context = ctx.as_mut();
|
2020-08-28 10:58:07 +00:00
|
|
|
let ptr = (ctx as *mut u8).sub(ALIGN_TO);
|
|
|
|
let bytes = (ptr as *mut usize).read();
|
|
|
|
let layout = alloc::Layout::from_size_align(bytes, ALIGN_TO).unwrap();
|
|
|
|
alloc::dealloc(ptr, layout);
|
2019-07-13 04:08:53 +00:00
|
|
|
}
|
|
|
|
|
2019-05-28 13:31:01 +00:00
|
|
|
/// **This function is an override for the C function, this is the an edited version of the original description:**
|
|
|
|
///
|
|
|
|
/// A callback function to be called when an illegal argument is passed to
|
|
|
|
/// an API call. It will only trigger for violations that are mentioned
|
|
|
|
/// explicitly in the header. **This will cause a panic**.
|
|
|
|
///
|
|
|
|
/// The philosophy is that these shouldn't be dealt with through a
|
|
|
|
/// specific return value, as calling code should not have branches to deal with
|
|
|
|
/// the case that this code itself is broken.
|
|
|
|
///
|
|
|
|
/// On the other hand, during debug stage, one would want to be informed about
|
|
|
|
/// such mistakes, and the default (crashing) may be inadvisable.
|
|
|
|
/// When this callback is triggered, the API function called is guaranteed not
|
|
|
|
/// to cause a crash, though its return value and output arguments are
|
|
|
|
/// undefined.
|
|
|
|
///
|
|
|
|
/// See also secp256k1_default_error_callback_fn.
|
|
|
|
///
|
2022-11-21 20:49:16 +00:00
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// `message` string should be a null terminated C string and, up to the first null byte, must be valid UTF8.
|
|
|
|
///
|
|
|
|
/// For exact safety constraints see [`std::slice::from_raw_parts`] and [`std::str::from_utf8_unchecked`].
|
2019-10-29 11:19:53 +00:00
|
|
|
#[no_mangle]
|
2020-12-22 15:35:16 +00:00
|
|
|
#[cfg(not(rust_secp_no_symbol_renaming))]
|
2022-12-20 21:11:14 +00:00
|
|
|
pub unsafe extern "C" fn rustsecp256k1_v0_8_0_default_illegal_callback_fn(message: *const c_char, _data: *mut c_void) {
|
2019-07-13 04:08:53 +00:00
|
|
|
use core::str;
|
2019-06-13 17:22:46 +00:00
|
|
|
let msg_slice = slice::from_raw_parts(message as *const u8, strlen(message));
|
|
|
|
let msg = str::from_utf8_unchecked(msg_slice);
|
|
|
|
panic!("[libsecp256k1] illegal argument. {}", msg);
|
2019-05-28 13:31:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// **This function is an override for the C function, this is the an edited version of the original description:**
|
|
|
|
///
|
|
|
|
/// A callback function to be called when an internal consistency check
|
|
|
|
/// fails. **This will cause a panic**.
|
|
|
|
///
|
|
|
|
/// This can only trigger in case of a hardware failure, miscompilation,
|
|
|
|
/// memory corruption, serious bug in the library, or other error would can
|
|
|
|
/// otherwise result in undefined behaviour. It will not trigger due to mere
|
|
|
|
/// incorrect usage of the API (see secp256k1_default_illegal_callback_fn
|
|
|
|
/// for that). After this callback returns, anything may happen, including
|
|
|
|
/// crashing.
|
|
|
|
///
|
|
|
|
/// See also secp256k1_default_illegal_callback_fn.
|
|
|
|
///
|
2022-11-21 20:49:16 +00:00
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// `message` string should be a null terminated C string and, up to the first null byte, must be valid UTF8.
|
|
|
|
///
|
|
|
|
/// For exact safety constraints see [`std::slice::from_raw_parts`] and [`std::str::from_utf8_unchecked`].
|
2019-10-29 11:19:53 +00:00
|
|
|
#[no_mangle]
|
2020-12-22 15:35:16 +00:00
|
|
|
#[cfg(not(rust_secp_no_symbol_renaming))]
|
2022-12-20 21:11:14 +00:00
|
|
|
pub unsafe extern "C" fn rustsecp256k1_v0_8_0_default_error_callback_fn(message: *const c_char, _data: *mut c_void) {
|
2019-07-13 04:08:53 +00:00
|
|
|
use core::str;
|
2019-06-13 17:22:46 +00:00
|
|
|
let msg_slice = slice::from_raw_parts(message as *const u8, strlen(message));
|
|
|
|
let msg = str::from_utf8_unchecked(msg_slice);
|
|
|
|
panic!("[libsecp256k1] internal consistency check failed {}", msg);
|
|
|
|
}
|
|
|
|
|
2022-11-21 20:49:16 +00:00
|
|
|
/// Returns the length of the `str_ptr` string.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// `str_ptr` must be valid pointer and point to a valid null terminated C string.
|
2020-12-22 15:35:16 +00:00
|
|
|
#[cfg(not(rust_secp_no_symbol_renaming))]
|
2019-06-13 17:22:46 +00:00
|
|
|
unsafe fn strlen(mut str_ptr: *const c_char) -> usize {
|
|
|
|
let mut ctr = 0;
|
|
|
|
while *str_ptr != '\0' as c_char {
|
|
|
|
ctr += 1;
|
|
|
|
str_ptr = str_ptr.offset(1);
|
|
|
|
}
|
|
|
|
ctr
|
2019-05-28 13:31:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-11-07 01:09:57 +00:00
|
|
|
/// A trait for producing pointers that will always be valid in C (assuming NULL pointer is a valid
|
|
|
|
/// no-op).
|
2020-05-13 11:50:57 +00:00
|
|
|
///
|
2022-11-07 01:09:57 +00:00
|
|
|
/// Rust does not guarantee pointers to Zero Sized Types
|
|
|
|
/// (<https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts>). In case the type
|
|
|
|
/// is empty this trait will return a NULL pointer, which should be handled in C.
|
2019-10-21 12:15:19 +00:00
|
|
|
pub trait CPtr {
|
2019-08-16 18:48:03 +00:00
|
|
|
type Target;
|
|
|
|
fn as_c_ptr(&self) -> *const Self::Target;
|
|
|
|
fn as_mut_c_ptr(&mut self) -> *mut Self::Target;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> CPtr for [T] {
|
|
|
|
type Target = T;
|
|
|
|
fn as_c_ptr(&self) -> *const Self::Target {
|
|
|
|
if self.is_empty() {
|
|
|
|
ptr::null()
|
|
|
|
} else {
|
|
|
|
self.as_ptr()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn as_mut_c_ptr(&mut self) -> *mut Self::Target {
|
|
|
|
if self.is_empty() {
|
2020-11-30 02:47:34 +00:00
|
|
|
ptr::null_mut::<Self::Target>()
|
2019-08-16 18:48:03 +00:00
|
|
|
} else {
|
|
|
|
self.as_mut_ptr()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-11 19:14:42 +00:00
|
|
|
#[cfg(fuzzing)]
|
2018-03-19 03:16:48 +00:00
|
|
|
mod fuzz_dummy {
|
2020-12-22 20:16:10 +00:00
|
|
|
use super::*;
|
2021-02-27 04:20:16 +00:00
|
|
|
use core::sync::atomic::{AtomicUsize, Ordering};
|
2018-03-19 03:16:48 +00:00
|
|
|
|
2021-02-18 14:55:46 +00:00
|
|
|
#[cfg(rust_secp_no_symbol_renaming)] compile_error!("We do not support fuzzing with rust_secp_no_symbol_renaming");
|
|
|
|
|
|
|
|
extern "C" {
|
2022-12-20 21:11:14 +00:00
|
|
|
fn rustsecp256k1_v0_8_0_context_preallocated_size(flags: c_uint) -> size_t;
|
|
|
|
fn rustsecp256k1_v0_8_0_context_preallocated_create(prealloc: NonNull<c_void>, flags: c_uint) -> NonNull<Context>;
|
|
|
|
fn rustsecp256k1_v0_8_0_context_preallocated_clone(cx: *const Context, prealloc: NonNull<c_void>) -> NonNull<Context>;
|
2021-02-18 14:55:46 +00:00
|
|
|
}
|
|
|
|
|
2021-02-27 04:20:16 +00:00
|
|
|
#[cfg(feature = "lowmemory")]
|
|
|
|
const CTX_SIZE: usize = 1024 * 65;
|
|
|
|
#[cfg(not(feature = "lowmemory"))]
|
|
|
|
const CTX_SIZE: usize = 1024 * (1024 + 128);
|
2021-02-18 14:55:46 +00:00
|
|
|
// Contexts
|
|
|
|
pub unsafe fn secp256k1_context_preallocated_size(flags: c_uint) -> size_t {
|
2022-12-20 21:11:14 +00:00
|
|
|
assert!(rustsecp256k1_v0_8_0_context_preallocated_size(flags) + std::mem::size_of::<c_uint>() <= CTX_SIZE);
|
2021-02-18 14:55:46 +00:00
|
|
|
CTX_SIZE
|
|
|
|
}
|
2021-02-27 04:20:16 +00:00
|
|
|
|
|
|
|
static HAVE_PREALLOCATED_CONTEXT: AtomicUsize = AtomicUsize::new(0);
|
|
|
|
const HAVE_CONTEXT_NONE: usize = 0;
|
|
|
|
const HAVE_CONTEXT_WORKING: usize = 1;
|
|
|
|
const HAVE_CONTEXT_DONE: usize = 2;
|
|
|
|
static mut PREALLOCATED_CONTEXT: [u8; CTX_SIZE] = [0; CTX_SIZE];
|
2022-12-01 04:22:24 +00:00
|
|
|
pub unsafe fn secp256k1_context_preallocated_create(prealloc: NonNull<c_void>, flags: c_uint) -> NonNull<Context> {
|
2021-02-27 04:20:16 +00:00
|
|
|
// While applications should generally avoid creating too many contexts, sometimes fuzzers
|
|
|
|
// perform tasks repeatedly which real applications may only do rarely. Thus, we want to
|
|
|
|
// avoid being overly slow here. We do so by having a static context and copying it into
|
|
|
|
// new buffers instead of recalculating it. Because we shouldn't rely on std, we use a
|
|
|
|
// simple hand-written OnceFlag built out of an atomic to gate the global static.
|
|
|
|
let mut have_ctx = HAVE_PREALLOCATED_CONTEXT.load(Ordering::Relaxed);
|
|
|
|
while have_ctx != HAVE_CONTEXT_DONE {
|
|
|
|
if have_ctx == HAVE_CONTEXT_NONE {
|
|
|
|
have_ctx = HAVE_PREALLOCATED_CONTEXT.swap(HAVE_CONTEXT_WORKING, Ordering::AcqRel);
|
|
|
|
if have_ctx == HAVE_CONTEXT_NONE {
|
2022-12-20 21:11:14 +00:00
|
|
|
assert!(rustsecp256k1_v0_8_0_context_preallocated_size(SECP256K1_START_SIGN | SECP256K1_START_VERIFY) + std::mem::size_of::<c_uint>() <= CTX_SIZE);
|
|
|
|
assert_eq!(rustsecp256k1_v0_8_0_context_preallocated_create(
|
2022-12-01 04:22:24 +00:00
|
|
|
NonNull::new_unchecked(PREALLOCATED_CONTEXT[..].as_mut_ptr() as *mut c_void),
|
2021-02-27 04:20:16 +00:00
|
|
|
SECP256K1_START_SIGN | SECP256K1_START_VERIFY),
|
2022-12-01 04:22:24 +00:00
|
|
|
NonNull::new_unchecked(PREALLOCATED_CONTEXT[..].as_mut_ptr() as *mut Context));
|
2021-02-27 04:20:16 +00:00
|
|
|
assert_eq!(HAVE_PREALLOCATED_CONTEXT.swap(HAVE_CONTEXT_DONE, Ordering::AcqRel),
|
|
|
|
HAVE_CONTEXT_WORKING);
|
|
|
|
} else if have_ctx == HAVE_CONTEXT_DONE {
|
|
|
|
// Another thread finished while we were swapping.
|
|
|
|
HAVE_PREALLOCATED_CONTEXT.store(HAVE_CONTEXT_DONE, Ordering::Release);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Another thread is building, just busy-loop until they're done.
|
|
|
|
assert_eq!(have_ctx, HAVE_CONTEXT_WORKING);
|
|
|
|
have_ctx = HAVE_PREALLOCATED_CONTEXT.load(Ordering::Acquire);
|
|
|
|
#[cfg(feature = "std")]
|
|
|
|
std::thread::yield_now();
|
|
|
|
}
|
|
|
|
}
|
2022-12-01 04:22:24 +00:00
|
|
|
ptr::copy_nonoverlapping(PREALLOCATED_CONTEXT[..].as_ptr(), prealloc.as_ptr() as *mut u8, CTX_SIZE);
|
|
|
|
let ptr = (prealloc.as_ptr()).add(CTX_SIZE).sub(std::mem::size_of::<c_uint>());
|
2021-02-18 14:55:46 +00:00
|
|
|
(ptr as *mut c_uint).write(flags);
|
2022-12-01 04:22:24 +00:00
|
|
|
NonNull::new_unchecked(prealloc.as_ptr() as *mut Context)
|
2021-02-18 14:55:46 +00:00
|
|
|
}
|
|
|
|
pub unsafe fn secp256k1_context_preallocated_clone_size(_cx: *const Context) -> size_t { CTX_SIZE }
|
2022-12-01 04:22:24 +00:00
|
|
|
pub unsafe fn secp256k1_context_preallocated_clone(cx: *const Context, prealloc: NonNull<c_void>) -> NonNull<Context> {
|
2021-02-18 14:55:46 +00:00
|
|
|
let orig_ptr = (cx as *mut u8).add(CTX_SIZE).sub(std::mem::size_of::<c_uint>());
|
2022-12-01 04:22:24 +00:00
|
|
|
let new_ptr = (prealloc.as_ptr() as *mut u8).add(CTX_SIZE).sub(std::mem::size_of::<c_uint>());
|
2021-02-18 14:55:46 +00:00
|
|
|
let flags = (orig_ptr as *mut c_uint).read();
|
|
|
|
(new_ptr as *mut c_uint).write(flags);
|
2022-12-20 21:11:14 +00:00
|
|
|
rustsecp256k1_v0_8_0_context_preallocated_clone(cx, prealloc)
|
2021-02-18 14:55:46 +00:00
|
|
|
}
|
|
|
|
|
2022-12-01 04:22:24 +00:00
|
|
|
pub unsafe fn secp256k1_context_randomize(cx: NonNull<Context>,
|
2021-02-27 04:20:48 +00:00
|
|
|
_seed32: *const c_uchar)
|
|
|
|
-> c_int {
|
|
|
|
// This function is really slow, and unsuitable for fuzzing
|
2022-12-01 04:22:24 +00:00
|
|
|
check_context_flags(cx.as_ptr(), 0);
|
2021-02-27 04:20:48 +00:00
|
|
|
1
|
|
|
|
}
|
|
|
|
|
2021-02-18 14:55:46 +00:00
|
|
|
unsafe fn check_context_flags(cx: *const Context, required_flags: c_uint) {
|
|
|
|
assert!(!cx.is_null());
|
|
|
|
let cx_flags = if cx == secp256k1_context_no_precomp {
|
|
|
|
1
|
|
|
|
} else {
|
|
|
|
let ptr = (cx as *const u8).add(CTX_SIZE).sub(std::mem::size_of::<c_uint>());
|
|
|
|
(ptr as *const c_uint).read()
|
|
|
|
};
|
|
|
|
assert_eq!(cx_flags & 1, 1); // SECP256K1_FLAGS_TYPE_CONTEXT
|
|
|
|
assert_eq!(cx_flags & required_flags, required_flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Checks that pk != 0xffff...ffff and pk[1..32] == pk[33..64]
|
|
|
|
unsafe fn test_pk_validate(cx: *const Context,
|
|
|
|
pk: *const PublicKey) -> c_int {
|
|
|
|
check_context_flags(cx, 0);
|
|
|
|
if (*pk).0[1..32] != (*pk).0[33..64] ||
|
|
|
|
((*pk).0[32] != 0 && (*pk).0[32] != 0xff) ||
|
|
|
|
secp256k1_ec_seckey_verify(cx, (*pk).0[0..32].as_ptr()) == 0 {
|
|
|
|
0
|
|
|
|
} else {
|
|
|
|
1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
unsafe fn test_cleanup_pk(pk: *mut PublicKey) {
|
|
|
|
(*pk).0[32..].copy_from_slice(&(*pk).0[..32]);
|
|
|
|
if (*pk).0[32] <= 0x7f {
|
|
|
|
(*pk).0[32] = 0;
|
|
|
|
} else {
|
|
|
|
(*pk).0[32] = 0xff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pubkeys
|
|
|
|
pub unsafe fn secp256k1_ec_pubkey_parse(cx: *const Context, pk: *mut PublicKey,
|
|
|
|
input: *const c_uchar, in_len: size_t)
|
|
|
|
-> c_int {
|
|
|
|
check_context_flags(cx, 0);
|
|
|
|
match in_len {
|
|
|
|
33 => {
|
|
|
|
if *input != 2 && *input != 3 {
|
|
|
|
0
|
|
|
|
} else {
|
|
|
|
ptr::copy(input.offset(1), (*pk).0[0..32].as_mut_ptr(), 32);
|
|
|
|
ptr::copy(input.offset(2), (*pk).0[33..64].as_mut_ptr(), 31);
|
|
|
|
if *input == 3 {
|
|
|
|
(*pk).0[32] = 0xff;
|
|
|
|
} else {
|
|
|
|
(*pk).0[32] = 0;
|
|
|
|
}
|
|
|
|
test_pk_validate(cx, pk)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
65 => {
|
|
|
|
if *input != 4 && *input != 6 && *input != 7 {
|
|
|
|
0
|
|
|
|
} else {
|
|
|
|
ptr::copy(input.offset(1), (*pk).0.as_mut_ptr(), 64);
|
|
|
|
test_cleanup_pk(pk);
|
|
|
|
test_pk_validate(cx, pk)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Serialize PublicKey back to 33/65 byte pubkey
|
|
|
|
pub unsafe fn secp256k1_ec_pubkey_serialize(cx: *const Context, output: *mut c_uchar,
|
|
|
|
out_len: *mut size_t, pk: *const PublicKey,
|
|
|
|
compressed: c_uint)
|
|
|
|
-> c_int {
|
|
|
|
check_context_flags(cx, 0);
|
|
|
|
assert_eq!(test_pk_validate(cx, pk), 1);
|
|
|
|
if compressed == SECP256K1_SER_COMPRESSED {
|
|
|
|
assert_eq!(*out_len, 33);
|
|
|
|
if (*pk).0[32] <= 0x7f {
|
|
|
|
*output = 2;
|
|
|
|
} else {
|
|
|
|
*output = 3;
|
|
|
|
}
|
|
|
|
ptr::copy((*pk).0.as_ptr(), output.offset(1), 32);
|
|
|
|
} else if compressed == SECP256K1_SER_UNCOMPRESSED {
|
|
|
|
assert_eq!(*out_len, 65);
|
|
|
|
*output = 4;
|
|
|
|
ptr::copy((*pk).0.as_ptr(), output.offset(1), 64);
|
|
|
|
} else {
|
|
|
|
panic!("Bad flags");
|
|
|
|
}
|
|
|
|
1
|
|
|
|
}
|
|
|
|
|
|
|
|
// EC
|
|
|
|
/// Sets pk to sk||sk
|
|
|
|
pub unsafe fn secp256k1_ec_pubkey_create(cx: *const Context, pk: *mut PublicKey,
|
|
|
|
sk: *const c_uchar) -> c_int {
|
|
|
|
check_context_flags(cx, SECP256K1_START_SIGN);
|
|
|
|
if secp256k1_ec_seckey_verify(cx, sk) != 1 { return 0; }
|
|
|
|
ptr::copy(sk, (*pk).0[0..32].as_mut_ptr(), 32);
|
|
|
|
test_cleanup_pk(pk);
|
|
|
|
assert_eq!(test_pk_validate(cx, pk), 1);
|
|
|
|
1
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn secp256k1_ec_pubkey_negate(cx: *const Context,
|
|
|
|
pk: *mut PublicKey) -> c_int {
|
|
|
|
check_context_flags(cx, 0);
|
|
|
|
assert_eq!(test_pk_validate(cx, pk), 1);
|
|
|
|
if secp256k1_ec_seckey_negate(cx, (*pk).0[..32].as_mut_ptr()) != 1 { return 0; }
|
|
|
|
test_cleanup_pk(pk);
|
|
|
|
assert_eq!(test_pk_validate(cx, pk), 1);
|
|
|
|
1
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The PublicKey equivalent of secp256k1_ec_privkey_tweak_add
|
|
|
|
pub unsafe fn secp256k1_ec_pubkey_tweak_add(cx: *const Context,
|
|
|
|
pk: *mut PublicKey,
|
|
|
|
tweak: *const c_uchar)
|
|
|
|
-> c_int {
|
|
|
|
check_context_flags(cx, SECP256K1_START_VERIFY);
|
|
|
|
assert_eq!(test_pk_validate(cx, pk), 1);
|
|
|
|
if secp256k1_ec_seckey_tweak_add(cx, (*pk).0[..32].as_mut_ptr(), tweak) != 1 { return 0; }
|
|
|
|
test_cleanup_pk(pk);
|
|
|
|
assert_eq!(test_pk_validate(cx, pk), 1);
|
|
|
|
1
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The PublicKey equivalent of secp256k1_ec_privkey_tweak_mul
|
|
|
|
pub unsafe fn secp256k1_ec_pubkey_tweak_mul(cx: *const Context,
|
|
|
|
pk: *mut PublicKey,
|
|
|
|
tweak: *const c_uchar)
|
|
|
|
-> c_int {
|
|
|
|
check_context_flags(cx, 0);
|
|
|
|
assert_eq!(test_pk_validate(cx, pk), 1);
|
|
|
|
if secp256k1_ec_seckey_tweak_mul(cx, (*pk).0[..32].as_mut_ptr(), tweak) != 1 { return 0; }
|
|
|
|
test_cleanup_pk(pk);
|
|
|
|
assert_eq!(test_pk_validate(cx, pk), 1);
|
|
|
|
1
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn secp256k1_ec_pubkey_combine(cx: *const Context,
|
|
|
|
out: *mut PublicKey,
|
|
|
|
ins: *const *const PublicKey,
|
|
|
|
n: c_int)
|
|
|
|
-> c_int {
|
|
|
|
check_context_flags(cx, 0);
|
|
|
|
assert!(n >= 1);
|
|
|
|
(*out) = **ins;
|
|
|
|
for i in 1..n {
|
|
|
|
assert_eq!(test_pk_validate(cx, *ins.offset(i as isize)), 1);
|
|
|
|
if secp256k1_ec_seckey_tweak_add(cx, (*out).0[..32].as_mut_ptr(), (**ins.offset(i as isize)).0[..32].as_ptr()) != 1 {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
test_cleanup_pk(out);
|
|
|
|
assert_eq!(test_pk_validate(cx, out), 1);
|
|
|
|
1
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Sets out to point^scalar^1s
|
|
|
|
pub unsafe fn secp256k1_ecdh(
|
|
|
|
cx: *const Context,
|
|
|
|
out: *mut c_uchar,
|
|
|
|
point: *const PublicKey,
|
|
|
|
scalar: *const c_uchar,
|
|
|
|
hashfp: EcdhHashFn,
|
|
|
|
data: *mut c_void,
|
|
|
|
) -> c_int {
|
|
|
|
check_context_flags(cx, 0);
|
|
|
|
assert_eq!(test_pk_validate(cx, point), 1);
|
|
|
|
if secp256k1_ec_seckey_verify(cx, scalar) != 1 { return 0; }
|
|
|
|
|
|
|
|
let scalar_slice = slice::from_raw_parts(scalar, 32);
|
|
|
|
let pk_slice = &(*point).0[..32];
|
|
|
|
|
2021-10-17 01:07:51 +00:00
|
|
|
let mut res_arr = [0u8; 32];
|
2021-02-18 14:55:46 +00:00
|
|
|
for i in 0..32 {
|
|
|
|
res_arr[i] = scalar_slice[i] ^ pk_slice[i] ^ 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(hashfn) = hashfp {
|
|
|
|
(hashfn)(out, res_arr.as_ptr(), res_arr.as_ptr(), data);
|
|
|
|
} else {
|
|
|
|
res_arr[16] = 0x00; // result should always be a valid secret key
|
|
|
|
let out_slice = slice::from_raw_parts_mut(out, 32);
|
|
|
|
out_slice.copy_from_slice(&res_arr);
|
|
|
|
}
|
|
|
|
1
|
|
|
|
}
|
|
|
|
|
2018-03-19 03:16:48 +00:00
|
|
|
// ECDSA
|
2020-12-22 20:16:10 +00:00
|
|
|
/// Verifies that sig is msg32||pk[..32]
|
2018-03-19 03:16:48 +00:00
|
|
|
pub unsafe fn secp256k1_ecdsa_verify(cx: *const Context,
|
|
|
|
sig: *const Signature,
|
|
|
|
msg32: *const c_uchar,
|
|
|
|
pk: *const PublicKey)
|
|
|
|
-> c_int {
|
2021-02-18 14:55:46 +00:00
|
|
|
check_context_flags(cx, SECP256K1_START_VERIFY);
|
2020-12-22 20:16:10 +00:00
|
|
|
// Actually verify
|
|
|
|
let sig_sl = slice::from_raw_parts(sig as *const u8, 64);
|
|
|
|
let msg_sl = slice::from_raw_parts(msg32 as *const u8, 32);
|
|
|
|
if &sig_sl[..32] == msg_sl && sig_sl[32..] == (*pk).0[0..32] {
|
2018-03-19 03:16:48 +00:00
|
|
|
1
|
2020-12-22 20:16:10 +00:00
|
|
|
} else {
|
|
|
|
0
|
2018-03-19 03:16:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-22 20:16:10 +00:00
|
|
|
/// Sets sig to msg32||pk[..32]
|
2018-03-19 03:16:48 +00:00
|
|
|
pub unsafe fn secp256k1_ecdsa_sign(cx: *const Context,
|
|
|
|
sig: *mut Signature,
|
|
|
|
msg32: *const c_uchar,
|
|
|
|
sk: *const c_uchar,
|
|
|
|
_noncefn: NonceFn,
|
|
|
|
_noncedata: *const c_void)
|
|
|
|
-> c_int {
|
2021-02-18 14:55:46 +00:00
|
|
|
check_context_flags(cx, SECP256K1_START_SIGN);
|
2020-12-22 20:16:10 +00:00
|
|
|
// Check context is built for signing (and compute pk)
|
|
|
|
let mut new_pk = PublicKey::new();
|
|
|
|
if secp256k1_ec_pubkey_create(cx, &mut new_pk, sk) != 1 {
|
|
|
|
return 0;
|
2018-03-19 03:16:48 +00:00
|
|
|
}
|
2020-12-22 20:16:10 +00:00
|
|
|
// Sign
|
|
|
|
let sig_sl = slice::from_raw_parts_mut(sig as *mut u8, 64);
|
|
|
|
let msg_sl = slice::from_raw_parts(msg32 as *const u8, 32);
|
|
|
|
sig_sl[..32].copy_from_slice(msg_sl);
|
|
|
|
sig_sl[32..].copy_from_slice(&new_pk.0[..32]);
|
2018-03-19 03:16:48 +00:00
|
|
|
1
|
|
|
|
}
|
|
|
|
|
2021-02-18 14:55:46 +00:00
|
|
|
// Schnorr Signatures
|
2020-12-22 20:16:10 +00:00
|
|
|
/// Verifies that sig is msg32||pk[32..]
|
|
|
|
pub unsafe fn secp256k1_schnorrsig_verify(
|
2018-11-06 21:36:43 +00:00
|
|
|
cx: *const Context,
|
2020-12-22 20:16:10 +00:00
|
|
|
sig64: *const c_uchar,
|
|
|
|
msg32: *const c_uchar,
|
2022-01-24 16:26:13 +00:00
|
|
|
msglen: size_t,
|
2020-12-22 20:16:10 +00:00
|
|
|
pubkey: *const XOnlyPublicKey,
|
2018-11-06 21:36:43 +00:00
|
|
|
) -> c_int {
|
2021-02-18 14:55:46 +00:00
|
|
|
check_context_flags(cx, SECP256K1_START_VERIFY);
|
2020-12-22 20:16:10 +00:00
|
|
|
// Check context is built for verification
|
|
|
|
let mut new_pk = PublicKey::new();
|
|
|
|
let _ = secp256k1_xonly_pubkey_tweak_add(cx, &mut new_pk, pubkey, msg32);
|
|
|
|
// Actually verify
|
|
|
|
let sig_sl = slice::from_raw_parts(sig64 as *const u8, 64);
|
2022-01-24 16:26:13 +00:00
|
|
|
let msg_sl = slice::from_raw_parts(msg32 as *const u8, msglen);
|
2020-12-22 20:16:10 +00:00
|
|
|
if &sig_sl[..32] == msg_sl && sig_sl[32..] == (*pubkey).0[..32] {
|
|
|
|
1
|
2018-03-29 15:21:13 +00:00
|
|
|
} else {
|
2020-12-22 20:16:10 +00:00
|
|
|
0
|
2018-03-29 15:21:13 +00:00
|
|
|
}
|
2018-03-19 03:16:48 +00:00
|
|
|
}
|
2020-09-15 01:42:20 +00:00
|
|
|
|
2020-12-22 20:16:10 +00:00
|
|
|
/// Sets sig to msg32||pk[..32]
|
2020-09-15 01:42:20 +00:00
|
|
|
pub unsafe fn secp256k1_schnorrsig_sign(
|
2020-12-22 20:16:10 +00:00
|
|
|
cx: *const Context,
|
|
|
|
sig64: *mut c_uchar,
|
|
|
|
msg32: *const c_uchar,
|
|
|
|
keypair: *const KeyPair,
|
2022-01-24 16:26:13 +00:00
|
|
|
_aux_rand32: *const c_uchar
|
2020-09-15 01:42:20 +00:00
|
|
|
) -> c_int {
|
2021-02-18 14:55:46 +00:00
|
|
|
check_context_flags(cx, SECP256K1_START_SIGN);
|
2020-12-22 20:16:10 +00:00
|
|
|
// Check context is built for signing
|
|
|
|
let mut new_kp = KeyPair::new();
|
|
|
|
if secp256k1_keypair_create(cx, &mut new_kp, (*keypair).0.as_ptr()) != 1 {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
assert_eq!(new_kp, *keypair);
|
|
|
|
// Sign
|
|
|
|
let sig_sl = slice::from_raw_parts_mut(sig64 as *mut u8, 64);
|
|
|
|
let msg_sl = slice::from_raw_parts(msg32 as *const u8, 32);
|
|
|
|
sig_sl[..32].copy_from_slice(msg_sl);
|
|
|
|
sig_sl[32..].copy_from_slice(&new_kp.0[32..64]);
|
|
|
|
1
|
2020-09-15 01:42:20 +00:00
|
|
|
}
|
2021-02-18 14:55:46 +00:00
|
|
|
|
2022-12-22 07:59:59 +00:00
|
|
|
|
|
|
|
// Forwards to regular schnorrsig_sign function.
|
|
|
|
pub unsafe fn secp256k1_schnorrsig_sign_custom(
|
|
|
|
cx: *const Context,
|
|
|
|
sig: *mut c_uchar,
|
|
|
|
msg: *const c_uchar,
|
|
|
|
_msg_len: size_t,
|
|
|
|
keypair: *const KeyPair,
|
|
|
|
_extra_params: *const SchnorrSigExtraParams,
|
|
|
|
) -> c_int {
|
|
|
|
secp256k1_schnorrsig_sign(cx, sig, msg, keypair, ptr::null())
|
|
|
|
}
|
|
|
|
|
2021-02-18 14:55:46 +00:00
|
|
|
// Extra keys
|
|
|
|
pub unsafe fn secp256k1_keypair_create(
|
|
|
|
cx: *const Context,
|
|
|
|
keypair: *mut KeyPair,
|
|
|
|
seckey: *const c_uchar,
|
|
|
|
) -> c_int {
|
|
|
|
check_context_flags(cx, SECP256K1_START_SIGN);
|
|
|
|
if secp256k1_ec_seckey_verify(cx, seckey) == 0 { return 0; }
|
|
|
|
|
|
|
|
let mut pk = PublicKey::new();
|
|
|
|
if secp256k1_ec_pubkey_create(cx, &mut pk, seckey) == 0 { return 0; }
|
|
|
|
|
|
|
|
let seckey_slice = slice::from_raw_parts(seckey, 32);
|
|
|
|
(*keypair).0[..32].copy_from_slice(seckey_slice);
|
|
|
|
(*keypair).0[32..].copy_from_slice(&pk.0);
|
|
|
|
1
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn secp256k1_xonly_pubkey_parse(
|
|
|
|
cx: *const Context,
|
|
|
|
pubkey: *mut XOnlyPublicKey,
|
|
|
|
input32: *const c_uchar,
|
|
|
|
) -> c_int {
|
|
|
|
check_context_flags(cx, 0);
|
|
|
|
let inslice = slice::from_raw_parts(input32, 32);
|
|
|
|
(*pubkey).0[..32].copy_from_slice(inslice);
|
|
|
|
(*pubkey).0[32..].copy_from_slice(inslice);
|
|
|
|
test_cleanup_pk(pubkey as *mut PublicKey);
|
|
|
|
test_pk_validate(cx, pubkey as *mut PublicKey)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn secp256k1_xonly_pubkey_serialize(
|
|
|
|
cx: *const Context,
|
|
|
|
output32: *mut c_uchar,
|
|
|
|
pubkey: *const XOnlyPublicKey,
|
|
|
|
) -> c_int {
|
|
|
|
check_context_flags(cx, 0);
|
|
|
|
let outslice = slice::from_raw_parts_mut(output32, 32);
|
|
|
|
outslice.copy_from_slice(&(*pubkey).0[..32]);
|
|
|
|
1
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn secp256k1_xonly_pubkey_from_pubkey(
|
|
|
|
cx: *const Context,
|
|
|
|
xonly_pubkey: *mut XOnlyPublicKey,
|
|
|
|
pk_parity: *mut c_int,
|
|
|
|
pubkey: *const PublicKey,
|
|
|
|
) -> c_int {
|
|
|
|
check_context_flags(cx, 0);
|
|
|
|
if !pk_parity.is_null() {
|
|
|
|
*pk_parity = ((*pubkey).0[32] == 0).into();
|
|
|
|
}
|
|
|
|
(*xonly_pubkey).0.copy_from_slice(&(*pubkey).0);
|
|
|
|
assert_eq!(test_pk_validate(cx, pubkey), 1);
|
|
|
|
1
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn secp256k1_xonly_pubkey_tweak_add(
|
|
|
|
cx: *const Context,
|
|
|
|
output_pubkey: *mut PublicKey,
|
|
|
|
internal_pubkey: *const XOnlyPublicKey,
|
|
|
|
tweak32: *const c_uchar,
|
|
|
|
) -> c_int {
|
|
|
|
check_context_flags(cx, SECP256K1_START_VERIFY);
|
|
|
|
(*output_pubkey).0.copy_from_slice(&(*internal_pubkey).0);
|
|
|
|
secp256k1_ec_pubkey_tweak_add(cx, output_pubkey, tweak32)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn secp256k1_keypair_xonly_pub(
|
|
|
|
cx: *const Context,
|
|
|
|
pubkey: *mut XOnlyPublicKey,
|
|
|
|
pk_parity: *mut c_int,
|
|
|
|
keypair: *const KeyPair
|
|
|
|
) -> c_int {
|
|
|
|
check_context_flags(cx, 0);
|
|
|
|
if !pk_parity.is_null() {
|
2022-06-14 08:27:33 +00:00
|
|
|
*pk_parity = ((*keypair).0[64] == 0).into();
|
2021-02-18 14:55:46 +00:00
|
|
|
}
|
|
|
|
(*pubkey).0.copy_from_slice(&(*keypair).0[32..]);
|
|
|
|
1
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn secp256k1_keypair_xonly_tweak_add(
|
|
|
|
cx: *const Context,
|
|
|
|
keypair: *mut KeyPair,
|
|
|
|
tweak32: *const c_uchar,
|
|
|
|
) -> c_int {
|
|
|
|
check_context_flags(cx, SECP256K1_START_VERIFY);
|
|
|
|
let mut pk = PublicKey::new();
|
|
|
|
pk.0.copy_from_slice(&(*keypair).0[32..]);
|
2021-10-17 01:07:51 +00:00
|
|
|
let mut sk = [0u8; 32];
|
2021-02-18 14:55:46 +00:00
|
|
|
sk.copy_from_slice(&(*keypair).0[..32]);
|
|
|
|
assert_eq!(secp256k1_ec_pubkey_tweak_add(cx, &mut pk, tweak32), 1);
|
|
|
|
assert_eq!(secp256k1_ec_seckey_tweak_add(cx, (&mut sk[..]).as_mut_ptr(), tweak32), 1);
|
|
|
|
(*keypair).0[..32].copy_from_slice(&sk);
|
|
|
|
(*keypair).0[32..].copy_from_slice(&pk.0);
|
|
|
|
1
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn secp256k1_xonly_pubkey_tweak_add_check(
|
|
|
|
cx: *const Context,
|
|
|
|
tweaked_pubkey32: *const c_uchar,
|
|
|
|
tweaked_pubkey_parity: c_int,
|
|
|
|
internal_pubkey: *const XOnlyPublicKey,
|
|
|
|
tweak32: *const c_uchar,
|
|
|
|
) -> c_int {
|
|
|
|
check_context_flags(cx, SECP256K1_START_VERIFY);
|
|
|
|
let mut tweaked_pk = PublicKey::new();
|
|
|
|
assert_eq!(secp256k1_xonly_pubkey_tweak_add(cx, &mut tweaked_pk, internal_pubkey, tweak32), 1);
|
|
|
|
let in_slice = slice::from_raw_parts(tweaked_pubkey32, 32);
|
|
|
|
if &tweaked_pk.0[..32] == in_slice && tweaked_pubkey_parity == (tweaked_pk.0[32] == 0).into() {
|
|
|
|
1
|
|
|
|
} else {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
}
|
2018-03-19 03:16:48 +00:00
|
|
|
}
|
2020-12-22 15:42:02 +00:00
|
|
|
|
2021-01-11 19:14:42 +00:00
|
|
|
#[cfg(fuzzing)]
|
2018-03-19 03:16:48 +00:00
|
|
|
pub use self::fuzz_dummy::*;
|
2019-06-13 17:22:46 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2020-12-22 15:35:16 +00:00
|
|
|
#[cfg(not(rust_secp_no_symbol_renaming))]
|
2019-06-13 17:22:46 +00:00
|
|
|
#[test]
|
|
|
|
fn test_strlen() {
|
2020-12-22 00:28:57 +00:00
|
|
|
use std::ffi::CString;
|
|
|
|
use super::strlen;
|
|
|
|
|
2019-06-13 17:22:46 +00:00
|
|
|
let orig = "test strlen \t \n";
|
|
|
|
let test = CString::new(orig).unwrap();
|
|
|
|
|
|
|
|
assert_eq!(orig.len(), unsafe {strlen(test.as_ptr())});
|
|
|
|
}
|
2019-08-08 17:20:36 +00:00
|
|
|
}
|
2019-10-21 12:15:19 +00:00
|
|
|
|