Merge rust-bitcoin/rust-secp256k1#627: Add bindings to the ElligatorSwift implementation

39febcb866 Create rust-bidings (Davidson Souza)

Pull request description:

  ~**Marking as draft as this is an unreleased feature from libsecp**~

  From upstream:
  This implements encoding of curve points using the ElligatorSwift algorithm, using 4 new API calls:

      secp256k1_ellswift_encode, which converts a public key to a 64-byte pseudorandom encoding.
      secp256k1_ellswift_decode, the reverse operation to convert back to normal public keys.
      secp256k1_ellswift_create, which can be seen as a combination of secp256k1_ec_pubkey_create + secp256k1_ellswift_encode, but is somewhat safer.
      secp256k1_ellswift_xdh, which implements x-only Diffie-Hellman directly on top of 64-byte encoded public keys, and more efficiently than decoding + invoking normal ECDH.

  This algorithm allows mapping any pair of field elements (u, t) to a (valid) x coordinate in the curve. This allows representing a field element as a 64-bytes bit string that is indistinguishable from random. You can build a pair of (u, t) from any group element as well.
  We also have an integrated x-only ECDH that can be used to establish a shared secret between two parties. All algorithms are compatible with BIP324 and are tested against the BIP's test cases.

  I have a few questions about the rust side of the implementation:
  Should it be always on, or leave it behind a cargo feature? In `libsecp` this module is default on, but you can disable it.
  I'm not exposing the low-level functions, instead you can use high-level types to interact with ellswift. Is it reasonable to also expose a safe version of the functions above?

ACKs for top commit:
  tcharding:
    ACK 39febcb866
  apoelstra:
    ACK 39febcb866

Tree-SHA512: a3c06304a03af9509ff3ef16fd39ee56ec22fc12d1b36be4c20aaa2ad01e98dd34ea64c66db782d3a2c10c3a7b44c701762d45f8d82f45b62db3379710c89c42
This commit is contained in:
Andrew Poelstra 2023-10-09 21:13:09 +00:00
commit 3aada83180
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
6 changed files with 822 additions and 1 deletions

View File

@ -23,7 +23,8 @@ fn main() {
.define("SECP256K1_API", Some("")) .define("SECP256K1_API", Some(""))
.define("ENABLE_MODULE_ECDH", Some("1")) .define("ENABLE_MODULE_ECDH", Some("1"))
.define("ENABLE_MODULE_SCHNORRSIG", Some("1")) .define("ENABLE_MODULE_SCHNORRSIG", Some("1"))
.define("ENABLE_MODULE_EXTRAKEYS", Some("1")); .define("ENABLE_MODULE_EXTRAKEYS", Some("1"))
.define("ENABLE_MODULE_ELLSWIFT", Some("1"));
if cfg!(feature = "lowmemory") { if cfg!(feature = "lowmemory") {
base_config.define("ECMULT_WINDOW_SIZE", Some("4")); // A low-enough value to consume negligible memory base_config.define("ECMULT_WINDOW_SIZE", Some("4")); // A low-enough value to consume negligible memory

View File

@ -82,6 +82,15 @@ pub type SchnorrNonceFn = Option<unsafe extern "C" fn(
data: *mut c_void, data: *mut c_void,
) -> c_int>; ) -> c_int>;
/// A hash function used by `ellswift_ecdh` to hash the final ECDH shared secret.
pub type EllswiftEcdhHashFn = Option<unsafe extern "C" fn(
output: *mut c_uchar,
x32: *const c_uchar,
ell_a64: *const c_uchar,
ell_b64: *const c_uchar,
data: *mut c_void,
) -> c_int>;
/// Data structure that contains additional arguments for schnorrsig_sign_custom. /// Data structure that contains additional arguments for schnorrsig_sign_custom.
#[repr(C)] #[repr(C)]
pub struct SchnorrSigExtraParams { pub struct SchnorrSigExtraParams {
@ -517,11 +526,32 @@ impl core::hash::Hash for Keypair {
} }
} }
/// Library-internal representation of a ElligatorSwift encoded group element.
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ElligatorSwift([u8; 64]);
impl ElligatorSwift {
pub fn from_array(arr: [u8; 64]) -> Self {
ElligatorSwift(arr)
}
pub fn to_array(self) -> [u8; 64] {
self.0
}
}
impl_array_newtype!(ElligatorSwift, u8, 64);
impl_raw_debug!(ElligatorSwift);
extern "C" { extern "C" {
/// Default ECDH hash function /// Default ECDH hash function
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_9_0_ecdh_hash_function_default")] #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_9_0_ecdh_hash_function_default")]
pub static secp256k1_ecdh_hash_function_default: EcdhHashFn; pub static secp256k1_ecdh_hash_function_default: EcdhHashFn;
/// Default ECDH hash function for BIP324 key establishment
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_9_0_ellswift_xdh_hash_function_bip324")]
pub static secp256k1_ellswift_xdh_hash_function_bip324: EllswiftEcdhHashFn;
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_9_0_nonce_function_rfc6979")] #[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_9_0_nonce_function_rfc6979")]
pub static secp256k1_nonce_function_rfc6979: NonceFn; pub static secp256k1_nonce_function_rfc6979: NonceFn;
@ -600,6 +630,34 @@ extern "C" {
output_pubkey: *mut PublicKey, output_pubkey: *mut PublicKey,
keypair: *const Keypair) keypair: *const Keypair)
-> c_int; -> c_int;
// Elligator Swift
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_9_0_ellswift_encode")]
pub fn secp256k1_ellswift_encode(ctx: *const Context,
ell64: *mut c_uchar,
pubkey: *const PublicKey,
rnd32: *const c_uchar)
-> c_int;
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_9_0_ellswift_decode")]
pub fn secp256k1_ellswift_decode(ctx: *const Context,
pubkey: *mut u8,
ell64: *const c_uchar)
-> c_int;
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_9_0_ellswift_create")]
pub fn secp256k1_ellswift_create(ctx: *const Context,
ell64: *mut c_uchar,
seckey32: *const c_uchar,
aux_rand32: *const c_uchar)
-> c_int;
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_9_0_ellswift_xdh")]
pub fn secp256k1_ellswift_xdh(ctx: *const Context,
output: *mut c_uchar,
ell_a64: *const c_uchar,
ell_b64: *const c_uchar,
seckey32: *const c_uchar,
party: c_int,
hashfp: EllswiftEcdhHashFn,
data: *mut c_void)
-> c_int;
} }
#[cfg(not(secp256k1_fuzz))] #[cfg(not(secp256k1_fuzz))]
@ -979,6 +1037,53 @@ impl<T> CPtr for [T] {
} }
} }
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() {
ptr::null_mut()
} else {
self.as_ptr() as *mut Self::Target
}
}
}
impl CPtr for [u8; 32] {
type Target = u8;
fn as_c_ptr(&self) -> *const Self::Target {
self.as_ptr()
}
fn as_mut_c_ptr(&mut self) -> *mut Self::Target {
self.as_mut_ptr()
}
}
impl <T: CPtr> CPtr for Option<T> {
type Target = T::Target;
fn as_mut_c_ptr(&mut self) -> *mut Self::Target {
match self {
Some(contents) => contents.as_mut_c_ptr(),
None => ptr::null_mut(),
}
}
fn as_c_ptr(&self) -> *const Self::Target {
match self {
Some(content) => content.as_c_ptr(),
None => ptr::null(),
}
}
}
#[cfg(secp256k1_fuzz)] #[cfg(secp256k1_fuzz)]
mod fuzz_dummy { mod fuzz_dummy {
use super::*; use super::*;

View File

@ -30,6 +30,9 @@ pub const SCHNORR_PUBLIC_KEY_SIZE: usize = 32;
/// The size of a key pair. /// The size of a key pair.
pub const KEY_PAIR_SIZE: usize = 96; pub const KEY_PAIR_SIZE: usize = 96;
/// The size of a full ElligatorSwift encoding.
pub const ELLSWIFT_ENCODING_SIZE: usize = 64;
/// The Prime for the secp256k1 field element. /// The Prime for the secp256k1 field element.
#[rustfmt::skip] #[rustfmt::skip]
pub const FIELD_SIZE: [u8; 32] = [ pub const FIELD_SIZE: [u8; 32] = [

703
src/ellswift.rs Normal file
View File

@ -0,0 +1,703 @@
// SPDX-License-Identifier: CC0-1.0
//! This module provides an implementation of ElligatorSwift as well as a
//! version of x-only ECDH using it (including compatibility with BIP324).
//!
//! `ElligatorSwift` is described in `https://eprint.iacr.org/2022/759` by
//! Chavez-Saab, Rodriguez-Henriquez, and Tibouchi. It permits encoding
//! uniformly chosen public keys as 64-byte arrays which are indistinguishable
//! from uniformly random arrays.
//!
//! Let f be the function from pairs of field elements to point X coordinates,
//! defined as follows (all operations modulo p = 2^256 - 2^32 - 977)
//! f(u,t):
//! - Let C = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852,
//! a square root of -3.
//! - If u=0, set u=1 instead.
//! - If t=0, set t=1 instead.
//! - If u^3 + t^2 + 7 = 0, multiply t by 2.
//! - Let X = (u^3 + 7 - t^2) / (2 * t)
//! - Let Y = (X + t) / (C * u)
//! - Return the first in [u + 4 * Y^2, (-X/Y - u) / 2, (X/Y - u) / 2] that is an
//! X coordinate on the curve (at least one of them is, for any u and t).
//!
//! Then an `ElligatorSwift` encoding of x consists of the 32-byte big-endian
//! encodings of field elements u and t concatenated, where f(u,t) = x.
//! The encoding algorithm is described in the paper, and effectively picks a
//! uniformly random pair (u,t) among those which encode x.
//!
//! If the Y coordinate is relevant, it is given the same parity as t.
//!
//! Changes w.r.t. the paper:
//! - The u=0, t=0, and u^3+t^2+7=0 conditions result in decoding to the point
//! at infinity in the paper. Here they are remapped to finite points.
//! - The paper uses an additional encoding bit for the parity of y. Here the
//! parity of t is used (negating t does not affect the decoded x coordinate,
//! so this is possible).
use core::fmt::{self, Display, Formatter};
use core::ptr;
use core::str::FromStr;
use ffi::CPtr;
use secp256k1_sys::types::{c_int, c_uchar, c_void};
use crate::{constants, ffi, from_hex, Error, PublicKey, Secp256k1, SecretKey, Verification};
unsafe extern "C" fn hash_callback<F>(
output: *mut c_uchar,
x32: *const c_uchar,
ell_a64: *const c_uchar,
ell_b64: *const c_uchar,
hash_func: *mut c_void,
) -> c_int
where
F: FnMut([u8; 32], [u8; 64], [u8; 64]) -> ElligatorSwiftSharedSecret,
{
let callback: &mut F = &mut *(hash_func as *mut F);
let mut x32_array = [0u8; 32];
let mut ell_a64_array = [0u8; 64];
let mut ell_b64_array = [0u8; 64];
// Copy the data into Rust slices
ptr::copy_nonoverlapping(x32, x32_array.as_mut_c_ptr(), 32);
ptr::copy_nonoverlapping(ell_a64, ell_a64_array.as_mut_c_ptr(), 64);
ptr::copy_nonoverlapping(ell_b64, ell_b64_array.as_mut_c_ptr(), 64);
// Call the hash function that was passed in through the `data` pointer
let secret = callback(x32_array, ell_a64_array, ell_b64_array);
// Copy the output from a [ElligatorSwiftSharedSecret] into the output pointer
ptr::copy_nonoverlapping(secret.0.as_ptr(), output, secret.0.len());
// Always returns 1
1
}
/// `ElligatorSwift` is an encoding of a uniformly chosen point on the curve
/// as a 64-byte array that is indistinguishable from a uniformly random array.
/// This object holds two field elements u and t, which are the inputs to
/// the `ElligatorSwift` encoding function.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ElligatorSwift(ffi::ElligatorSwift);
impl ElligatorSwift {
/// Create a new `ElligatorSwift` object from a 64-byte array.
pub fn new(secret_key: SecretKey, rand: [u8; 32]) -> ElligatorSwift {
let mut ell_out = [0u8; constants::ELLSWIFT_ENCODING_SIZE];
unsafe {
let ret = ffi::secp256k1_ellswift_create(
ffi::secp256k1_context_no_precomp,
ell_out.as_mut_c_ptr(),
secret_key.as_c_ptr(),
rand.as_ptr(),
);
debug_assert_eq!(ret, 1);
}
ElligatorSwift(ffi::ElligatorSwift::from_array(ell_out))
}
/// Creates an `ElligatorSwift` object from a 64-byte array.
pub fn from_array(ellswift: [u8; 64]) -> ElligatorSwift {
ElligatorSwift(ffi::ElligatorSwift::from_array(ellswift))
}
/// Returns the 64-byte array representation of this `ElligatorSwift` object.
pub fn to_array(&self) -> [u8; 64] { self.0.to_array() }
/// Creates the Elligator Swift encoding from a secret key, using some aux_rand if defined.
/// This method is preferred instead of just decoding, because the private key offers extra
/// entropy.
/// # Example
/// ```
/// # #[cfg(feature = "alloc")] {
/// use secp256k1::{ellswift::ElligatorSwift, PublicKey, Secp256k1, SecretKey};
/// let secp = Secp256k1::new();
/// let sk = SecretKey::from_slice(&[1; 32]).unwrap();
/// let es = ElligatorSwift::from_seckey(&secp, sk, None);
/// # }
/// ```
pub fn from_seckey<C: Verification>(
secp: &Secp256k1<C>,
sk: SecretKey,
aux_rand: Option<[u8; 32]>,
) -> ElligatorSwift {
let mut es_out = [0u8; constants::ELLSWIFT_ENCODING_SIZE];
let aux_rand_ptr = aux_rand.as_c_ptr();
unsafe {
let ret = ffi::secp256k1_ellswift_create(
secp.ctx().as_ptr(),
es_out.as_mut_c_ptr(),
sk.as_c_ptr(),
aux_rand_ptr,
);
debug_assert_eq!(ret, 1);
}
ElligatorSwift(ffi::ElligatorSwift::from_array(es_out))
}
/// Computes the `ElligatorSwift` encoding for a valid public key
/// # Example
/// ```
/// # #[cfg(feature = "alloc")] {
/// use secp256k1::{ellswift::ElligatorSwift, PublicKey, Secp256k1, SecretKey};
/// let secp = Secp256k1::new();
/// let sk = SecretKey::from_slice(&[1; 32]).unwrap();
/// let pk = PublicKey::from_secret_key(&secp, &sk);
/// let es = ElligatorSwift::from_pubkey(pk);
/// # }
///
/// ```
pub fn from_pubkey(pk: PublicKey) -> ElligatorSwift { Self::encode(pk) }
/// Computes a shared secret only known by Alice and Bob. This is obtained by computing
/// the x-only Elliptic Curve Diffie-Hellman (ECDH) shared secret between Alice and Bob.
/// # Example
/// ```
/// # #[cfg(feature = "alloc")] {
/// use secp256k1::{
/// ellswift::{ElligatorSwift, ElligatorSwiftParty},
/// PublicKey, SecretKey, XOnlyPublicKey, Secp256k1,
/// };
/// use core::str::FromStr;
///
/// let secp = Secp256k1::new();
///
/// let alice_sk = SecretKey::from_str("e714e76bdd67ad9f495683c37934148f4efc25ce3f01652c8a906498339e1f3a").unwrap();
/// let bob_sk = SecretKey::from_str("b6c4b0e2f8c4359caf356a618cd1649d18790a1d67f7c2d1e4760e04c785db4f").unwrap();
///
/// let alice_es = ElligatorSwift::from_seckey(&secp, alice_sk, None);
/// let bob_es = ElligatorSwift::from_seckey(&secp, bob_sk, None);
///
/// let alice_shared_secret = ElligatorSwift::shared_secret(alice_es, bob_es, alice_sk, ElligatorSwiftParty::A, None);
/// let bob_shared_secret = ElligatorSwift::shared_secret(alice_es, bob_es, bob_sk, ElligatorSwiftParty::B, None);
///
/// assert_eq!(alice_shared_secret, bob_shared_secret);
/// # }
/// ```
pub fn shared_secret(
ellswift_a: ElligatorSwift,
ellswift_b: ElligatorSwift,
secret_key: SecretKey,
party: ElligatorSwiftParty,
data: Option<&[u8]>,
) -> ElligatorSwiftSharedSecret {
let mut shared_secret = [0u8; 32];
unsafe {
let ret = ffi::secp256k1_ellswift_xdh(
ffi::secp256k1_context_no_precomp,
shared_secret.as_mut_c_ptr(),
ellswift_a.as_c_ptr(),
ellswift_b.as_c_ptr(),
secret_key.as_c_ptr(),
party.to_ffi_int(),
ffi::secp256k1_ellswift_xdh_hash_function_bip324,
data.as_c_ptr() as *mut c_void,
);
debug_assert_eq!(ret, 1);
}
ElligatorSwiftSharedSecret(shared_secret)
}
/// Computes a shared secret, just like `shared_secret`, but with a custom hash function
/// for computing the shared secret. For compatibility with other libraries, you should
/// use `shared_secret` instead, which is already compatible with BIP324.
/// The hash function takes three arguments: the shared point, and the `ElligatorSwift`
/// encodings of the two parties and returns a 32-byte shared secret.
pub fn shared_secret_with_hasher<F>(
ellswift_a: ElligatorSwift,
ellswift_b: ElligatorSwift,
secret_key: SecretKey,
party: ElligatorSwiftParty,
mut hash_function: F,
) -> ElligatorSwiftSharedSecret
where
F: FnMut([u8; 32], [u8; 64], [u8; 64]) -> ElligatorSwiftSharedSecret,
{
let mut shared_secret = [0u8; 32];
let hashfp = hash_callback::<F>;
unsafe {
let ret = ffi::secp256k1_ellswift_xdh(
ffi::secp256k1_context_no_precomp,
shared_secret.as_mut_c_ptr(),
ellswift_a.0.as_c_ptr(),
ellswift_b.0.as_c_ptr(),
secret_key.as_c_ptr(),
party.to_ffi_int(),
Some(hashfp),
&mut hash_function as *mut F as *mut c_void,
);
debug_assert_eq!(ret, 1);
}
ElligatorSwiftSharedSecret(shared_secret)
}
/// Encodes a public key into an `ElligatorSwift` encoding
fn encode(pk: PublicKey) -> ElligatorSwift {
let mut ell_out = [0u8; constants::ELLSWIFT_ENCODING_SIZE];
unsafe {
let ret = ffi::secp256k1_ellswift_encode(
ffi::secp256k1_context_no_precomp,
ell_out.as_mut_c_ptr(),
pk.as_c_ptr(),
[0u8; 32].as_ptr(),
);
debug_assert_eq!(ret, 1);
}
ElligatorSwift(ffi::ElligatorSwift::from_array(ell_out))
}
/// Decodes an `ElligatorSwift` encoding into a [`PublicKey`].
pub(crate) fn decode(ell: ElligatorSwift) -> PublicKey {
unsafe {
let mut pk = ffi::PublicKey::new();
let ret = ffi::secp256k1_ellswift_decode(
ffi::secp256k1_context_no_precomp,
pk.as_mut_c_ptr(),
ell.as_c_ptr(),
);
debug_assert_eq!(ret, 1);
PublicKey::from(pk)
}
}
}
/// The result of `ElligatorSwift::shared_secret`, which is a shared secret
/// computed from the x-only ECDH using both parties' public keys (`ElligatorSwift` encoded) and our own
/// private key.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ElligatorSwiftSharedSecret([u8; 32]);
/// Represents which party we are in the ECDH, A is the initiator, B is the responder.
/// This is important because the hash of the shared secret is different depending on which party
/// we are. In this context, "we" means the party that is using this library, and possesses the
/// secret key passed to `ElligatorSwift::shared_secret`.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ElligatorSwiftParty {
/// We are the initiator of the ECDH
A,
/// We are the responder of the ECDH
B,
}
impl ElligatorSwiftParty {
fn to_ffi_int(self) -> c_int {
match self {
ElligatorSwiftParty::A => 0,
ElligatorSwiftParty::B => 1,
}
}
}
impl FromStr for ElligatorSwift {
fn from_str(hex: &str) -> Result<Self, Self::Err> {
let mut ser = [0u8; 64];
let parsed = from_hex(hex, &mut ser);
match parsed {
Ok(64) => Ok(ElligatorSwift::from_array(ser)),
_ => Err(Error::InvalidEllSwift),
}
}
type Err = Error;
}
impl fmt::LowerHex for ElligatorSwift {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let ser = self.to_array();
for ch in ser.iter() {
write!(f, "{:02x}", ch)?;
}
Ok(())
}
}
impl Display for ElligatorSwift {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { core::fmt::LowerHex::fmt(&self, f) }
}
impl ffi::CPtr for ElligatorSwift {
type Target = u8;
fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.0.as_mut_c_ptr() }
fn as_c_ptr(&self) -> *const Self::Target { self.0.as_c_ptr() }
}
#[cfg(test)]
mod tests {
use core::str::FromStr;
use crate::ellswift::ElligatorSwift;
#[cfg(all(not(secp256k1_fuzz), feature = "alloc"))]
use crate::ellswift::{ElligatorSwiftParty, ElligatorSwiftSharedSecret};
#[cfg(all(not(secp256k1_fuzz), feature = "alloc"))]
use crate::SecretKey;
use crate::{from_hex, PublicKey, XOnlyPublicKey};
#[test]
#[cfg(all(not(secp256k1_fuzz), feature = "alloc"))]
fn test_elligator_swift_rtt() {
// Test that we can round trip an ElligatorSwift encoding
let secp = crate::Secp256k1::new();
let public_key =
PublicKey::from_secret_key(&secp, &SecretKey::from_slice(&[1u8; 32]).unwrap());
let ell = ElligatorSwift::from_pubkey(public_key);
let pk = PublicKey::from_ellswift(ell);
assert_eq!(pk, public_key);
}
#[test]
#[cfg(all(not(secp256k1_fuzz), feature = "alloc"))]
fn test_create_elligator_swift_create_rtt() {
// Test that we can round trip an ElligatorSwift created from a secret key
let secp = crate::Secp256k1::new();
let rand32 = [1u8; 32];
let priv32 = [1u8; 32];
let ell = ElligatorSwift::from_seckey(&secp, SecretKey::from_slice(&rand32).unwrap(), None);
let pk = PublicKey::from_ellswift(ell);
let expected = PublicKey::from_secret_key(&secp, &SecretKey::from_slice(&priv32).unwrap());
assert_eq!(pk, expected);
}
#[test]
#[cfg(all(not(secp256k1_fuzz), feature = "alloc"))]
fn test_xdh_with_custom_hasher() {
// Test the ECDH with a custom hash function
let secp = crate::Secp256k1::new();
let rand32 = [1u8; 32];
let priv32 = [2u8; 32];
let ell = ElligatorSwift::from_seckey(
&secp,
SecretKey::from_slice(&rand32).unwrap(),
Some(rand32),
);
let pk = ElligatorSwift::shared_secret_with_hasher(
ell,
ell,
SecretKey::from_slice(&priv32).unwrap(),
ElligatorSwiftParty::A,
|_, _, _| ElligatorSwiftSharedSecret([0xff; 32]),
);
assert_eq!(pk, ElligatorSwiftSharedSecret([0xff; 32]));
}
#[test]
#[cfg(all(not(secp256k1_fuzz), feature = "alloc"))]
fn ellswift_ecdh_test() {
let tests = vec![
(
[
0x61, 0x06, 0x2e, 0xa5, 0x07, 0x1d, 0x80, 0x0b, 0xbf, 0xd5, 0x9e, 0x2e, 0x8b,
0x53, 0xd4, 0x7d, 0x19, 0x4b, 0x09, 0x5a, 0xe5, 0xa4, 0xdf, 0x04, 0x93, 0x6b,
0x49, 0x77, 0x2e, 0xf0, 0xd4, 0xd7,
],
[
0xec, 0x0a, 0xdf, 0xf2, 0x57, 0xbb, 0xfe, 0x50, 0x0c, 0x18, 0x8c, 0x80, 0xb4,
0xfd, 0xd6, 0x40, 0xf6, 0xb4, 0x5a, 0x48, 0x2b, 0xbc, 0x15, 0xfc, 0x7c, 0xef,
0x59, 0x31, 0xde, 0xff, 0x0a, 0xa1, 0x86, 0xf6, 0xeb, 0x9b, 0xba, 0x7b, 0x85,
0xdc, 0x4d, 0xcc, 0x28, 0xb2, 0x87, 0x22, 0xde, 0x1e, 0x3d, 0x91, 0x08, 0xb9,
0x85, 0xe2, 0x96, 0x70, 0x45, 0x66, 0x8f, 0x66, 0x09, 0x8e, 0x47, 0x5b,
],
[
0xa4, 0xa9, 0x4d, 0xfc, 0xe6, 0x9b, 0x4a, 0x2a, 0x0a, 0x09, 0x93, 0x13, 0xd1,
0x0f, 0x9f, 0x7e, 0x7d, 0x64, 0x9d, 0x60, 0x50, 0x1c, 0x9e, 0x1d, 0x27, 0x4c,
0x30, 0x0e, 0x0d, 0x89, 0xaa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xaf, 0x88, 0xd5,
],
1,
[
0xc6, 0x99, 0x2a, 0x11, 0x7f, 0x5e, 0xdb, 0xea, 0x70, 0xc3, 0xf5, 0x11, 0xd3,
0x2d, 0x26, 0xb9, 0x79, 0x8b, 0xe4, 0xb8, 0x1a, 0x62, 0xea, 0xee, 0x1a, 0x5a,
0xca, 0xa8, 0x45, 0x9a, 0x35, 0x92,
],
),
(
[
0x1f, 0x9c, 0x58, 0x1b, 0x35, 0x23, 0x18, 0x38, 0xf0, 0xf1, 0x7c, 0xf0, 0xc9,
0x79, 0x83, 0x5b, 0xac, 0xcb, 0x7f, 0x3a, 0xbb, 0xbb, 0x96, 0xff, 0xcc, 0x31,
0x8a, 0xb7, 0x1e, 0x6e, 0x12, 0x6f,
],
[
0xa1, 0x85, 0x5e, 0x10, 0xe9, 0x4e, 0x00, 0xba, 0xa2, 0x30, 0x41, 0xd9, 0x16,
0xe2, 0x59, 0xf7, 0x04, 0x4e, 0x49, 0x1d, 0xa6, 0x17, 0x12, 0x69, 0x69, 0x47,
0x63, 0xf0, 0x18, 0xc7, 0xe6, 0x36, 0x93, 0xd2, 0x95, 0x75, 0xdc, 0xb4, 0x64,
0xac, 0x81, 0x6b, 0xaa, 0x1b, 0xe3, 0x53, 0xba, 0x12, 0xe3, 0x87, 0x6c, 0xba,
0x76, 0x28, 0xbd, 0x0b, 0xd8, 0xe7, 0x55, 0xe7, 0x21, 0xeb, 0x01, 0x40,
],
[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
],
0,
[
0xa0, 0x13, 0x8f, 0x56, 0x4f, 0x74, 0xd0, 0xad, 0x70, 0xbc, 0x33, 0x7d, 0xac,
0xc9, 0xd0, 0xbf, 0x1d, 0x23, 0x49, 0x36, 0x4c, 0xaf, 0x11, 0x88, 0xa1, 0xe6,
0xe8, 0xdd, 0xb3, 0xb7, 0xb1, 0x84,
],
),
(
[
0x02, 0x86, 0xc4, 0x1c, 0xd3, 0x09, 0x13, 0xdb, 0x0f, 0xdf, 0xf7, 0xa6, 0x4e,
0xbd, 0xa5, 0xc8, 0xe3, 0xe7, 0xce, 0xf1, 0x0f, 0x2a, 0xeb, 0xc0, 0x0a, 0x76,
0x50, 0x44, 0x3c, 0xf4, 0xc6, 0x0d,
],
[
0xd1, 0xee, 0x8a, 0x93, 0xa0, 0x11, 0x30, 0xcb, 0xf2, 0x99, 0x24, 0x9a, 0x25,
0x8f, 0x94, 0xfe, 0xb5, 0xf4, 0x69, 0xe7, 0xd0, 0xf2, 0xf2, 0x8f, 0x69, 0xee,
0x5e, 0x9a, 0xa8, 0xf9, 0xb5, 0x4a, 0x60, 0xf2, 0xc3, 0xff, 0x2d, 0x02, 0x36,
0x34, 0xec, 0x7f, 0x41, 0x27, 0xa9, 0x6c, 0xc1, 0x16, 0x62, 0xe4, 0x02, 0x89,
0x4c, 0xf1, 0xf6, 0x94, 0xfb, 0x9a, 0x7e, 0xaa, 0x5f, 0x1d, 0x92, 0x44,
],
[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x22, 0xd5, 0xe4, 0x41, 0x52, 0x4d, 0x57, 0x1a, 0x52, 0xb3, 0xde,
0xf1, 0x26, 0x18, 0x9d, 0x3f, 0x41, 0x68, 0x90, 0xa9, 0x9d, 0x4d, 0xa6, 0xed,
0xe2, 0xb0, 0xcd, 0xe1, 0x76, 0x0c, 0xe2, 0xc3, 0xf9, 0x84, 0x57, 0xae,
],
1,
[
0x25, 0x0b, 0x93, 0x57, 0x0d, 0x41, 0x11, 0x49, 0x10, 0x5a, 0xb8, 0xcb, 0x0b,
0xc5, 0x07, 0x99, 0x14, 0x90, 0x63, 0x06, 0x36, 0x8c, 0x23, 0xe9, 0xd7, 0x7c,
0x2a, 0x33, 0x26, 0x5b, 0x99, 0x4c,
],
),
(
[
0x6c, 0x77, 0x43, 0x2d, 0x1f, 0xda, 0x31, 0xe9, 0xf9, 0x42, 0xf8, 0xaf, 0x44,
0x60, 0x7e, 0x10, 0xf3, 0xad, 0x38, 0xa6, 0x5f, 0x8a, 0x4b, 0xdd, 0xae, 0x82,
0x3e, 0x5e, 0xff, 0x90, 0xdc, 0x38,
],
[
0xd2, 0x68, 0x50, 0x70, 0xc1, 0xe6, 0x37, 0x6e, 0x63, 0x3e, 0x82, 0x52, 0x96,
0x63, 0x4f, 0xd4, 0x61, 0xfa, 0x9e, 0x5b, 0xdf, 0x21, 0x09, 0xbc, 0xeb, 0xd7,
0x35, 0xe5, 0xa9, 0x1f, 0x3e, 0x58, 0x7c, 0x5c, 0xb7, 0x82, 0xab, 0xb7, 0x97,
0xfb, 0xf6, 0xbb, 0x50, 0x74, 0xfd, 0x15, 0x42, 0xa4, 0x74, 0xf2, 0xa4, 0x5b,
0x67, 0x37, 0x63, 0xec, 0x2d, 0xb7, 0xfb, 0x99, 0xb7, 0x37, 0xbb, 0xb9,
],
[
0x56, 0xbd, 0x0c, 0x06, 0xf1, 0x03, 0x52, 0xc3, 0xa1, 0xa9, 0xf4, 0xb4, 0xc9,
0x2f, 0x6f, 0xa2, 0xb2, 0x6d, 0xf1, 0x24, 0xb5, 0x78, 0x78, 0x35, 0x3c, 0x1f,
0xc6, 0x91, 0xc5, 0x1a, 0xbe, 0xa7, 0x7c, 0x88, 0x17, 0xda, 0xee, 0xb9, 0xfa,
0x54, 0x6b, 0x77, 0xc8, 0xda, 0xf7, 0x9d, 0x89, 0xb2, 0x2b, 0x0e, 0x1b, 0x87,
0x57, 0x4e, 0xce, 0x42, 0x37, 0x1f, 0x00, 0x23, 0x7a, 0xa9, 0xd8, 0x3a,
],
0,
[
0x19, 0x18, 0xb7, 0x41, 0xef, 0x5f, 0x9d, 0x1d, 0x76, 0x70, 0xb0, 0x50, 0xc1,
0x52, 0xb4, 0xa4, 0xea, 0xd2, 0xc3, 0x1b, 0xe9, 0xae, 0xcb, 0x06, 0x81, 0xc0,
0xcd, 0x43, 0x24, 0x15, 0x08, 0x53,
],
),
(
[
0xa6, 0xec, 0x25, 0x12, 0x7c, 0xa1, 0xaa, 0x4c, 0xf1, 0x6b, 0x20, 0x08, 0x4b,
0xa1, 0xe6, 0x51, 0x6b, 0xaa, 0xe4, 0xd3, 0x24, 0x22, 0x28, 0x8e, 0x9b, 0x36,
0xd8, 0xbd, 0xdd, 0x2d, 0xe3, 0x5a,
],
[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x05, 0x3d, 0x7e, 0xcc, 0xa5, 0x3e, 0x33, 0xe1, 0x85, 0xa8, 0xb9,
0xbe, 0x4e, 0x76, 0x99, 0xa9, 0x7c, 0x6f, 0xf4, 0xc7, 0x95, 0x52, 0x2e, 0x59,
0x18, 0xab, 0x7c, 0xd6, 0xb6, 0x88, 0x4f, 0x67, 0xe6, 0x83, 0xf3, 0xdc,
],
[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xa7, 0x73, 0x0b, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
],
1,
[
0xdd, 0x21, 0x0a, 0xa6, 0x62, 0x9f, 0x20, 0xbb, 0x32, 0x8e, 0x5d, 0x89, 0xda,
0xa6, 0xeb, 0x2a, 0xc3, 0xd1, 0xc6, 0x58, 0xa7, 0x25, 0x53, 0x6f, 0xf1, 0x54,
0xf3, 0x1b, 0x53, 0x6c, 0x23, 0xb2,
],
),
(
[
0x0a, 0xf9, 0x52, 0x65, 0x9e, 0xd7, 0x6f, 0x80, 0xf5, 0x85, 0x96, 0x6b, 0x95,
0xab, 0x6e, 0x6f, 0xd6, 0x86, 0x54, 0x67, 0x28, 0x27, 0x87, 0x86, 0x84, 0xc8,
0xb5, 0x47, 0xb1, 0xb9, 0x4f, 0x5a,
],
[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xc8, 0x10, 0x17, 0xfd, 0x92, 0xfd, 0x31, 0x63, 0x7c, 0x26, 0xc9,
0x06, 0xb4, 0x20, 0x92, 0xe1, 0x1c, 0xc0, 0xd3, 0xaf, 0xae, 0x8d, 0x90, 0x19,
0xd2, 0x57, 0x8a, 0xf2, 0x27, 0x35, 0xce, 0x7b, 0xc4, 0x69, 0xc7, 0x2d,
],
[
0x96, 0x52, 0xd7, 0x8b, 0xae, 0xfc, 0x02, 0x8c, 0xd3, 0x7a, 0x6a, 0x92, 0x62,
0x5b, 0x8b, 0x8f, 0x85, 0xfd, 0xe1, 0xe4, 0xc9, 0x44, 0xad, 0x3f, 0x20, 0xe1,
0x98, 0xbe, 0xf8, 0xc0, 0x2f, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf2, 0xe9, 0x18, 0x70,
],
0,
[
0x35, 0x68, 0xf2, 0xae, 0xa2, 0xe1, 0x4e, 0xf4, 0xee, 0x4a, 0x3c, 0x2a, 0x8b,
0x8d, 0x31, 0xbc, 0x5e, 0x31, 0x87, 0xba, 0x86, 0xdb, 0x10, 0x73, 0x9b, 0x4f,
0xf8, 0xec, 0x92, 0xff, 0x66, 0x55,
],
),
(
[
0xf9, 0x0e, 0x08, 0x0c, 0x64, 0xb0, 0x58, 0x24, 0xc5, 0xa2, 0x4b, 0x25, 0x01,
0xd5, 0xae, 0xaf, 0x08, 0xaf, 0x38, 0x72, 0xee, 0x86, 0x0a, 0xa8, 0x0b, 0xdc,
0xd4, 0x30, 0xf7, 0xb6, 0x34, 0x94,
],
[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x11, 0x51, 0x73, 0x76, 0x5d, 0xc2, 0x02, 0xcf, 0x02, 0x9a, 0xd3,
0xf1, 0x54, 0x79, 0x73, 0x5d, 0x57, 0x69, 0x7a, 0xf1, 0x2b, 0x01, 0x31, 0xdd,
0x21, 0x43, 0x0d, 0x57, 0x72, 0xe4, 0xef, 0x11, 0x47, 0x4d, 0x58, 0xb9,
],
[
0x12, 0xa5, 0x0f, 0x3f, 0xaf, 0xea, 0x7c, 0x1e, 0xea, 0xda, 0x4c, 0xf8, 0xd3,
0x37, 0x77, 0x70, 0x4b, 0x77, 0x36, 0x14, 0x53, 0xaf, 0xc8, 0x3b, 0xda, 0x91,
0xee, 0xf3, 0x49, 0xae, 0x04, 0x4d, 0x20, 0x12, 0x6c, 0x62, 0x00, 0x54, 0x7e,
0xa5, 0xa6, 0x91, 0x17, 0x76, 0xc0, 0x5d, 0xee, 0x2a, 0x7f, 0x1a, 0x9b, 0xa7,
0xdf, 0xba, 0xbb, 0xbd, 0x27, 0x3c, 0x3e, 0xf2, 0x9e, 0xf4, 0x6e, 0x46,
],
1,
[
0xe2, 0x54, 0x61, 0xfb, 0x0e, 0x4c, 0x16, 0x2e, 0x18, 0x12, 0x3e, 0xcd, 0xe8,
0x83, 0x42, 0xd5, 0x4d, 0x44, 0x96, 0x31, 0xe9, 0xb7, 0x5a, 0x26, 0x6f, 0xd9,
0x26, 0x0c, 0x2b, 0xb2, 0xf4, 0x1d,
],
),
];
for (my_secret, ellswift_ours, ellswift_theirs, initiator, shared_secret) in tests {
// We are not the initiator, so we are B
let (el_a, el_b) = if initiator == 0 {
(
ElligatorSwift::from_array(ellswift_theirs),
ElligatorSwift::from_array(ellswift_ours),
)
} else {
// We are the initiator, so we are A
(
ElligatorSwift::from_array(ellswift_ours),
ElligatorSwift::from_array(ellswift_theirs),
)
};
let sec_key = SecretKey::from_slice(&my_secret).unwrap();
let initiator =
if initiator == 0 { ElligatorSwiftParty::B } else { ElligatorSwiftParty::A };
let shared = ElligatorSwift::shared_secret(el_a, el_b, sec_key, initiator, None);
assert_eq!(shared.0, shared_secret);
}
}
#[test]
#[cfg(not(secp256k1_fuzz))]
fn ellswift_decode_test() {
struct EllswiftDecodeTest {
enc: [u8; 64],
key: PublicKey,
}
#[inline]
fn parse_test(ell: &str, x: &str, parity: u32) -> EllswiftDecodeTest {
let mut enc = [0u8; 64];
from_hex(ell, &mut enc).unwrap();
let xo = XOnlyPublicKey::from_str(x).unwrap();
let parity = if parity == 0 { crate::Parity::Even } else { crate::Parity::Odd };
let pk = PublicKey::from_x_only_public_key(xo, parity);
EllswiftDecodeTest { enc, key: pk }
}
macro_rules! make_tests {
($(($ell: literal, $x: literal, $parity: literal)),+) => {
[$(
parse_test($ell, $x, $parity),
)+]
};
}
let tests = make_tests!(
("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","edd1fd3e327ce90cc7a3542614289aee9682003e9cf7dcc9cf2ca9743be5aa0c", 0),
("000000000000000000000000000000000000000000000000000000000000000001d3475bf7655b0fb2d852921035b2ef607f49069b97454e6795251062741771","b5da00b73cd6560520e7c364086e7cd23a34bf60d0e707be9fc34d4cd5fdfa2c", 1),
("000000000000000000000000000000000000000000000000000000000000000082277c4a71f9d22e66ece523f8fa08741a7c0912c66a69ce68514bfd3515b49f","f482f2e241753ad0fb89150d8491dc1e34ff0b8acfbb442cfe999e2e5e6fd1d2", 1),
("00000000000000000000000000000000000000000000000000000000000000008421cc930e77c9f514b6915c3dbe2a94c6d8f690b5b739864ba6789fb8a55dd0","9f59c40275f5085a006f05dae77eb98c6fd0db1ab4a72ac47eae90a4fc9e57e0", 0),
("0000000000000000000000000000000000000000000000000000000000000000bde70df51939b94c9c24979fa7dd04ebd9b3572da7802290438af2a681895441","aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9fffffd6b", 1),
("0000000000000000000000000000000000000000000000000000000000000000d19c182d2759cd99824228d94799f8c6557c38a1c0d6779b9d4b729c6f1ccc42","70720db7e238d04121f5b1afd8cc5ad9d18944c6bdc94881f502b7a3af3aecff", 0),
("0000000000000000000000000000000000000000000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","edd1fd3e327ce90cc7a3542614289aee9682003e9cf7dcc9cf2ca9743be5aa0c", 0),
("0000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff2664bbd5","50873db31badcc71890e4f67753a65757f97aaa7dd5f1e82b753ace32219064b", 0),
("0000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff7028de7d","1eea9cc59cfcf2fa151ac6c274eea4110feb4f7b68c5965732e9992e976ef68e", 0),
("0000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffcbcfb7e7","12303941aedc208880735b1f1795c8e55be520ea93e103357b5d2adb7ed59b8e", 0),
("0000000000000000000000000000000000000000000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffff3113ad9","7eed6b70e7b0767c7d7feac04e57aa2a12fef5e0f48f878fcbb88b3b6b5e0783", 0),
("0a2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f8530000000000000000000000000000000000000000000000000000000000000000","532167c11200b08c0e84a354e74dcc40f8b25f4fe686e30869526366278a0688", 0),
("0a2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f853fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","532167c11200b08c0e84a354e74dcc40f8b25f4fe686e30869526366278a0688", 0),
("0ffde9ca81d751e9cdaffc1a50779245320b28996dbaf32f822f20117c22fbd6c74d99efceaa550f1ad1c0f43f46e7ff1ee3bd0162b7bf55f2965da9c3450646","74e880b3ffd18fe3cddf7902522551ddf97fa4a35a3cfda8197f947081a57b8f", 0),
("0ffde9ca81d751e9cdaffc1a50779245320b28996dbaf32f822f20117c22fbd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffff156ca896","377b643fce2271f64e5c8101566107c1be4980745091783804f654781ac9217c", 1),
("123658444f32be8f02ea2034afa7ef4bbe8adc918ceb49b12773b625f490b368ffffffffffffffffffffffffffffffffffffffffffffffffffffffff8dc5fe11","ed16d65cf3a9538fcb2c139f1ecbc143ee14827120cbc2659e667256800b8142", 0),
("146f92464d15d36e35382bd3ca5b0f976c95cb08acdcf2d5b3570617990839d7ffffffffffffffffffffffffffffffffffffffffffffffffffffffff3145e93b","0d5cd840427f941f65193079ab8e2e83024ef2ee7ca558d88879ffd879fb6657", 0),
("15fdf5cf09c90759add2272d574d2bb5fe1429f9f3c14c65e3194bf61b82aa73ffffffffffffffffffffffffffffffffffffffffffffffffffffffff04cfd906","16d0e43946aec93f62d57eb8cde68951af136cf4b307938dd1447411e07bffe1", 1),
("1f67edf779a8a649d6def60035f2fa22d022dd359079a1a144073d84f19b92d50000000000000000000000000000000000000000000000000000000000000000","025661f9aba9d15c3118456bbe980e3e1b8ba2e047c737a4eb48a040bb566f6c", 0),
("1f67edf779a8a649d6def60035f2fa22d022dd359079a1a144073d84f19b92d5fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","025661f9aba9d15c3118456bbe980e3e1b8ba2e047c737a4eb48a040bb566f6c", 0),
("1fe1e5ef3fceb5c135ab7741333ce5a6e80d68167653f6b2b24bcbcfaaaff507fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","98bec3b2a351fa96cfd191c1778351931b9e9ba9ad1149f6d9eadca80981b801", 0),
("4056a34a210eec7892e8820675c860099f857b26aad85470ee6d3cf1304a9dcf375e70374271f20b13c9986ed7d3c17799698cfc435dbed3a9f34b38c823c2b4","868aac2003b29dbcad1a3e803855e078a89d16543ac64392d122417298cec76e", 0),
("4197ec3723c654cfdd32ab075506648b2ff5070362d01a4fff14b336b78f963fffffffffffffffffffffffffffffffffffffffffffffffffffffffffb3ab1e95","ba5a6314502a8952b8f456e085928105f665377a8ce27726a5b0eb7ec1ac0286", 0),
("47eb3e208fedcdf8234c9421e9cd9a7ae873bfbdbc393723d1ba1e1e6a8e6b24ffffffffffffffffffffffffffffffffffffffffffffffffffffffff7cd12cb1","d192d52007e541c9807006ed0468df77fd214af0a795fe119359666fdcf08f7c", 0),
("5eb9696a2336fe2c3c666b02c755db4c0cfd62825c7b589a7b7bb442e141c1d693413f0052d49e64abec6d5831d66c43612830a17df1fe4383db896468100221","ef6e1da6d6c7627e80f7a7234cb08a022c1ee1cf29e4d0f9642ae924cef9eb38", 1),
("7bf96b7b6da15d3476a2b195934b690a3a3de3e8ab8474856863b0de3af90b0e0000000000000000000000000000000000000000000000000000000000000000","50851dfc9f418c314a437295b24feeea27af3d0cd2308348fda6e21c463e46ff", 0),
("7bf96b7b6da15d3476a2b195934b690a3a3de3e8ab8474856863b0de3af90b0efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","50851dfc9f418c314a437295b24feeea27af3d0cd2308348fda6e21c463e46ff", 0),
("851b1ca94549371c4f1f7187321d39bf51c6b7fb61f7cbf027c9da62021b7a65fc54c96837fb22b362eda63ec52ec83d81bedd160c11b22d965d9f4a6d64d251","3e731051e12d33237eb324f2aa5b16bb868eb49a1aa1fadc19b6e8761b5a5f7b", 1),
("943c2f775108b737fe65a9531e19f2fc2a197f5603e3a2881d1d83e4008f91250000000000000000000000000000000000000000000000000000000000000000","311c61f0ab2f32b7b1f0223fa72f0a78752b8146e46107f8876dd9c4f92b2942", 0),
("943c2f775108b737fe65a9531e19f2fc2a197f5603e3a2881d1d83e4008f9125fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","311c61f0ab2f32b7b1f0223fa72f0a78752b8146e46107f8876dd9c4f92b2942", 0),
("a0f18492183e61e8063e573606591421b06bc3513631578a73a39c1c3306239f2f32904f0d2a33ecca8a5451705bb537d3bf44e071226025cdbfd249fe0f7ad6","97a09cf1a2eae7c494df3c6f8a9445bfb8c09d60832f9b0b9d5eabe25fbd14b9", 0),
("a1ed0a0bd79d8a23cfe4ec5fef5ba5cccfd844e4ff5cb4b0f2e71627341f1c5b17c499249e0ac08d5d11ea1c2c8ca7001616559a7994eadec9ca10fb4b8516dc","65a89640744192cdac64b2d21ddf989cdac7500725b645bef8e2200ae39691f2", 0),
("ba94594a432721aa3580b84c161d0d134bc354b690404d7cd4ec57c16d3fbe98ffffffffffffffffffffffffffffffffffffffffffffffffffffffffea507dd7","5e0d76564aae92cb347e01a62afd389a9aa401c76c8dd227543dc9cd0efe685a", 0),
("bcaf7219f2f6fbf55fe5e062dce0e48c18f68103f10b8198e974c184750e1be3932016cbf69c4471bd1f656c6a107f1973de4af7086db897277060e25677f19a","2d97f96cac882dfe73dc44db6ce0f1d31d6241358dd5d74eb3d3b50003d24c2b", 0),
("bcaf7219f2f6fbf55fe5e062dce0e48c18f68103f10b8198e974c184750e1be3ffffffffffffffffffffffffffffffffffffffffffffffffffffffff6507d09a","e7008afe6e8cbd5055df120bd748757c686dadb41cce75e4addcc5e02ec02b44", 1),
("c5981bae27fd84401c72a155e5707fbb811b2b620645d1028ea270cbe0ee225d4b62aa4dca6506c1acdbecc0552569b4b21436a5692e25d90d3bc2eb7ce24078","948b40e7181713bc018ec1702d3d054d15746c59a7020730dd13ecf985a010d7", 0),
("c894ce48bfec433014b931a6ad4226d7dbd8eaa7b6e3faa8d0ef94052bcf8cff336eeb3919e2b4efb746c7f71bbca7e9383230fbbc48ffafe77e8bcc69542471","f1c91acdc2525330f9b53158434a4d43a1c547cff29f15506f5da4eb4fe8fa5a", 1),
("cbb0deab125754f1fdb2038b0434ed9cb3fb53ab735391129994a535d925f6730000000000000000000000000000000000000000000000000000000000000000","872d81ed8831d9998b67cb7105243edbf86c10edfebb786c110b02d07b2e67cd", 0),
("d917b786dac35670c330c9c5ae5971dfb495c8ae523ed97ee2420117b171f41effffffffffffffffffffffffffffffffffffffffffffffffffffffff2001f6f6","e45b71e110b831f2bdad8651994526e58393fde4328b1ec04d59897142584691", 1),
("e28bd8f5929b467eb70e04332374ffb7e7180218ad16eaa46b7161aa679eb4260000000000000000000000000000000000000000000000000000000000000000","66b8c980a75c72e598d383a35a62879f844242ad1e73ff12edaa59f4e58632b5", 0),
("e28bd8f5929b467eb70e04332374ffb7e7180218ad16eaa46b7161aa679eb426fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","66b8c980a75c72e598d383a35a62879f844242ad1e73ff12edaa59f4e58632b5", 0),
("e7ee5814c1706bf8a89396a9b032bc014c2cac9c121127dbf6c99278f8bb53d1dfd04dbcda8e352466b6fcd5f2dea3e17d5e133115886eda20db8a12b54de71b","e842c6e3529b234270a5e97744edc34a04d7ba94e44b6d2523c9cf0195730a50", 1),
("f292e46825f9225ad23dc057c1d91c4f57fcb1386f29ef10481cb1d22518593fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7011c989","3cea2c53b8b0170166ac7da67194694adacc84d56389225e330134dab85a4d55", 0),
("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0000000000000000000000000000000000000000000000000000000000000000","edd1fd3e327ce90cc7a3542614289aee9682003e9cf7dcc9cf2ca9743be5aa0c", 0),
("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f01d3475bf7655b0fb2d852921035b2ef607f49069b97454e6795251062741771","b5da00b73cd6560520e7c364086e7cd23a34bf60d0e707be9fc34d4cd5fdfa2c", 1),
("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f4218f20ae6c646b363db68605822fb14264ca8d2587fdd6fbc750d587e76a7ee","aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9fffffd6b", 0),
("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f82277c4a71f9d22e66ece523f8fa08741a7c0912c66a69ce68514bfd3515b49f","f482f2e241753ad0fb89150d8491dc1e34ff0b8acfbb442cfe999e2e5e6fd1d2", 1),
("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8421cc930e77c9f514b6915c3dbe2a94c6d8f690b5b739864ba6789fb8a55dd0","9f59c40275f5085a006f05dae77eb98c6fd0db1ab4a72ac47eae90a4fc9e57e0", 0),
("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fd19c182d2759cd99824228d94799f8c6557c38a1c0d6779b9d4b729c6f1ccc42","70720db7e238d04121f5b1afd8cc5ad9d18944c6bdc94881f502b7a3af3aecff", 0),
("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","edd1fd3e327ce90cc7a3542614289aee9682003e9cf7dcc9cf2ca9743be5aa0c", 0),
("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fffffffffffffffffffffffffffffffffffffffffffffffffffffffff2664bbd5","50873db31badcc71890e4f67753a65757f97aaa7dd5f1e82b753ace32219064b", 0),
("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7028de7d","1eea9cc59cfcf2fa151ac6c274eea4110feb4f7b68c5965732e9992e976ef68e", 0),
("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fffffffffffffffffffffffffffffffffffffffffffffffffffffffffcbcfb7e7","12303941aedc208880735b1f1795c8e55be520ea93e103357b5d2adb7ed59b8e", 0),
("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3113ad9","7eed6b70e7b0767c7d7feac04e57aa2a12fef5e0f48f878fcbb88b3b6b5e0783", 0),
("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff13cea4a70000000000000000000000000000000000000000000000000000000000000000","649984435b62b4a25d40c6133e8d9ab8c53d4b059ee8a154a3be0fcf4e892edb", 0),
("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff13cea4a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","649984435b62b4a25d40c6133e8d9ab8c53d4b059ee8a154a3be0fcf4e892edb", 0),
("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff15028c590063f64d5a7f1c14915cd61eac886ab295bebd91992504cf77edb028bdd6267f","3fde5713f8282eead7d39d4201f44a7c85a5ac8a0681f35e54085c6b69543374", 1),
("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff2715de860000000000000000000000000000000000000000000000000000000000000000","3524f77fa3a6eb4389c3cb5d27f1f91462086429cd6c0cb0df43ea8f1e7b3fb4", 0),
("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff2715de86fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","3524f77fa3a6eb4389c3cb5d27f1f91462086429cd6c0cb0df43ea8f1e7b3fb4", 0),
("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff2c2c5709e7156c417717f2feab147141ec3da19fb759575cc6e37b2ea5ac9309f26f0f66","d2469ab3e04acbb21c65a1809f39caafe7a77c13d10f9dd38f391c01dc499c52", 0),
("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff3a08cc1efffffffffffffffffffffffffffffffffffffffffffffffffffffffff760e9f0","38e2a5ce6a93e795e16d2c398bc99f0369202ce21e8f09d56777b40fc512bccc", 1),
("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff3e91257d932016cbf69c4471bd1f656c6a107f1973de4af7086db897277060e25677f19a","864b3dc902c376709c10a93ad4bbe29fce0012f3dc8672c6286bba28d7d6d6fc", 0),
("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff795d6c1c322cadf599dbb86481522b3cc55f15a67932db2afa0111d9ed6981bcd124bf44","766dfe4a700d9bee288b903ad58870e3d4fe2f0ef780bcac5c823f320d9a9bef", 0),
("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff8e426f0392389078c12b1a89e9542f0593bc96b6bfde8224f8654ef5d5cda935a3582194","faec7bc1987b63233fbc5f956edbf37d54404e7461c58ab8631bc68e451a0478", 0),
("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff91192139ffffffffffffffffffffffffffffffffffffffffffffffffffffffff45f0f1eb","ec29a50bae138dbf7d8e24825006bb5fc1a2cc1243ba335bc6116fb9e498ec1f", 0),
("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff98eb9ab76e84499c483b3bf06214abfe065dddf43b8601de596d63b9e45a166a580541fe","1e0ff2dee9b09b136292a9e910f0d6ac3e552a644bba39e64e9dd3e3bbd3d4d4", 0),
("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff9b77b7f2c74d99efceaa550f1ad1c0f43f46e7ff1ee3bd0162b7bf55f2965da9c3450646","8b7dd5c3edba9ee97b70eff438f22dca9849c8254a2f3345a0a572ffeaae0928", 0),
("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff9b77b7f2ffffffffffffffffffffffffffffffffffffffffffffffffffffffff156ca896","0881950c8f51d6b9a6387465d5f12609ef1bb25412a08a74cb2dfb200c74bfbf", 1),
("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffa2f5cd838816c16c4fe8a1661d606fdb13cf9af04b979a2e159a09409ebc8645d58fde02","2f083207b9fd9b550063c31cd62b8746bd543bdc5bbf10e3a35563e927f440c8", 0),
("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffb13f75c00000000000000000000000000000000000000000000000000000000000000000","4f51e0be078e0cddab2742156adba7e7a148e73157072fd618cd60942b146bd0", 0),
("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffb13f75c0fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","4f51e0be078e0cddab2742156adba7e7a148e73157072fd618cd60942b146bd0", 0),
("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7bc1f8d0000000000000000000000000000000000000000000000000000000000000000","16c2ccb54352ff4bd794f6efd613c72197ab7082da5b563bdf9cb3edaafe74c2", 0),
("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7bc1f8dfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","16c2ccb54352ff4bd794f6efd613c72197ab7082da5b563bdf9cb3edaafe74c2", 0),
("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffef64d162750546ce42b0431361e52d4f5242d8f24f33e6b1f99b591647cbc808f462af51","d41244d11ca4f65240687759f95ca9efbab767ededb38fd18c36e18cd3b6f6a9", 1),
("fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0e5be52372dd6e894b2a326fc3605a6e8f3c69c710bf27d630dfe2004988b78eb6eab36","64bf84dd5e03670fdb24c0f5d3c2c365736f51db6c92d95010716ad2d36134c8", 0),
("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffefbb982fffffffffffffffffffffffffffffffffffffffffffffffffffffffff6d6db1f","1c92ccdfcf4ac550c28db57cff0c8515cb26936c786584a70114008d6c33a34b", 0)
);
for test in tests.iter() {
let pk = PublicKey::from_ellswift(ElligatorSwift::from_array(test.enc));
assert_eq!(pk, test.key);
}
}
}

View File

@ -10,6 +10,7 @@ use core::{fmt, ptr, str};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::ser::SerializeTuple; use serde::ser::SerializeTuple;
use crate::ellswift::ElligatorSwift;
use crate::ffi::types::c_uint; use crate::ffi::types::c_uint;
use crate::ffi::{self, CPtr}; use crate::ffi::{self, CPtr};
use crate::Error::{self, InvalidPublicKey, InvalidPublicKeySum, InvalidSecretKey}; use crate::Error::{self, InvalidPublicKey, InvalidPublicKeySum, InvalidSecretKey};
@ -450,6 +451,9 @@ impl PublicKey {
PublicKey(pk) PublicKey(pk)
} }
} }
/// Creates a new public key from an [`ElligatorSwift`].
#[inline]
pub fn from_ellswift(ellswift: ElligatorSwift) -> PublicKey { ElligatorSwift::decode(ellswift) }
/// Creates a new public key from a [`SecretKey`] and the global [`SECP256K1`] context. /// Creates a new public key from a [`SecretKey`] and the global [`SECP256K1`] context.
#[inline] #[inline]

View File

@ -164,6 +164,7 @@ mod key;
pub mod constants; pub mod constants;
pub mod ecdh; pub mod ecdh;
pub mod ecdsa; pub mod ecdsa;
pub mod ellswift;
pub mod scalar; pub mod scalar;
pub mod schnorr; pub mod schnorr;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
@ -334,6 +335,8 @@ pub enum Error {
InvalidPublicKeySum, InvalidPublicKeySum,
/// The only valid parity values are 0 or 1. /// The only valid parity values are 0 or 1.
InvalidParityValue(key::InvalidParityValue), InvalidParityValue(key::InvalidParityValue),
/// Bad EllSwift value
InvalidEllSwift,
} }
impl fmt::Display for Error { impl fmt::Display for Error {
@ -354,6 +357,7 @@ impl fmt::Display for Error {
"the sum of public keys was invalid or the input vector lengths was less than 1", "the sum of public keys was invalid or the input vector lengths was less than 1",
), ),
InvalidParityValue(e) => write_err!(f, "couldn't create parity"; e), InvalidParityValue(e) => write_err!(f, "couldn't create parity"; e),
InvalidEllSwift => f.write_str("malformed EllSwift value"),
} }
} }
} }
@ -373,6 +377,7 @@ impl std::error::Error for Error {
Error::NotEnoughMemory => None, Error::NotEnoughMemory => None,
Error::InvalidPublicKeySum => None, Error::InvalidPublicKeySum => None,
Error::InvalidParityValue(error) => Some(error), Error::InvalidParityValue(error) => Some(error),
Error::InvalidEllSwift => None,
} }
} }
} }