secp256k1/
ellswift.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! This module provides an implementation of ElligatorSwift as well as a
4//! version of x-only ECDH using it (including compatibility with BIP324).
5//!
6//! `ElligatorSwift` is described in `https://eprint.iacr.org/2022/759` by
7//! Chavez-Saab, Rodriguez-Henriquez, and Tibouchi. It permits encoding
8//! uniformly chosen public keys as 64-byte arrays which are indistinguishable
9//! from uniformly random arrays.
10//!
11//! Let f be the function from pairs of field elements to point X coordinates,
12//! defined as follows (all operations modulo p = 2^256 - 2^32 - 977)
13//! f(u,t):
14//! - Let C = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852,
15//!   a square root of -3.
16//! - If u=0, set u=1 instead.
17//! - If t=0, set t=1 instead.
18//! - If u^3 + t^2 + 7 = 0, multiply t by 2.
19//! - Let X = (u^3 + 7 - t^2) / (2 * t)
20//! - Let Y = (X + t) / (C * u)
21//! - Return the first in [u + 4 * Y^2, (-X/Y - u) / 2, (X/Y - u) / 2] that is an
22//!   X coordinate on the curve (at least one of them is, for any u and t).
23//!
24//! Then an `ElligatorSwift` encoding of x consists of the 32-byte big-endian
25//! encodings of field elements u and t concatenated, where f(u,t) = x.
26//! The encoding algorithm is described in the paper, and effectively picks a
27//! uniformly random pair (u,t) among those which encode x.
28//!
29//! If the Y coordinate is relevant, it is given the same parity as t.
30//!
31//! Changes w.r.t. the paper:
32//! - The u=0, t=0, and u^3+t^2+7=0 conditions result in decoding to the point
33//!   at infinity in the paper. Here they are remapped to finite points.
34//! - The paper uses an additional encoding bit for the parity of y. Here the
35//!   parity of t is used (negating t does not affect the decoded x coordinate,
36//!   so this is possible).
37
38use core::fmt::{self, Display, Formatter};
39use core::ptr;
40use core::str::FromStr;
41
42use ffi::CPtr;
43use secp256k1_sys::types::{c_int, c_uchar, c_void};
44
45use crate::{constants, ffi, from_hex, Error, PublicKey, Secp256k1, SecretKey};
46
47unsafe extern "C" fn hash_callback<F>(
48    output: *mut c_uchar,
49    x32: *const c_uchar,
50    ell_a64: *const c_uchar,
51    ell_b64: *const c_uchar,
52    hash_func: *mut c_void,
53) -> c_int
54where
55    F: FnMut([u8; 32], [u8; 64], [u8; 64]) -> ElligatorSwiftSharedSecret,
56{
57    let callback: &mut F = &mut *(hash_func as *mut F);
58    let mut x32_array = [0u8; 32];
59    let mut ell_a64_array = [0u8; 64];
60    let mut ell_b64_array = [0u8; 64];
61
62    // Copy the data into Rust slices
63    ptr::copy_nonoverlapping(x32, x32_array.as_mut_c_ptr(), 32);
64    ptr::copy_nonoverlapping(ell_a64, ell_a64_array.as_mut_c_ptr(), 64);
65    ptr::copy_nonoverlapping(ell_b64, ell_b64_array.as_mut_c_ptr(), 64);
66    // Call the hash function that was passed in through the `data` pointer
67    let secret = callback(x32_array, ell_a64_array, ell_b64_array);
68    // Copy the output from a [ElligatorSwiftSharedSecret] into the output pointer
69    ptr::copy_nonoverlapping(secret.0.as_ptr(), output, secret.0.len());
70    // Always returns 1
71    1
72}
73
74/// An encoding of an elliptic curvepoint such that a uniformly random on-curve
75/// point will be encoded as uniformly random bits.
76///
77/// This object holds two field elements u and t, which are the inputs to
78/// the `ElligatorSwift` encoding function.
79#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
80pub struct ElligatorSwift(ffi::ElligatorSwift);
81
82impl ElligatorSwift {
83    /// Create a new `ElligatorSwift` object from a 64-byte array.
84    pub fn new(secret_key: SecretKey, rand: [u8; 32]) -> ElligatorSwift {
85        let mut ell_out = [0u8; constants::ELLSWIFT_ENCODING_SIZE];
86        unsafe {
87            let ret = ffi::secp256k1_ellswift_create(
88                ffi::secp256k1_context_no_precomp,
89                ell_out.as_mut_c_ptr(),
90                secret_key.as_c_ptr(),
91                rand.as_ptr(),
92            );
93            debug_assert_eq!(ret, 1);
94        }
95        ElligatorSwift(ffi::ElligatorSwift::from_array(ell_out))
96    }
97
98    /// Creates an `ElligatorSwift` object from a 64-byte array.
99    pub fn from_array(ellswift: [u8; 64]) -> ElligatorSwift {
100        ElligatorSwift(ffi::ElligatorSwift::from_array(ellswift))
101    }
102
103    /// Returns the 64-byte array representation of this `ElligatorSwift` object.
104    pub fn to_array(&self) -> [u8; 64] { self.0.to_array() }
105
106    /// Creates the Elligator Swift encoding from a secret key, using some aux_rand if defined.
107    /// This method is preferred instead of just decoding, because the private key offers extra
108    /// entropy.
109    /// # Example
110    /// ```
111    /// # #[cfg(feature = "alloc")] {
112    ///     use secp256k1::{ellswift::ElligatorSwift, PublicKey, SecretKey};
113    ///     let sk = SecretKey::from_secret_bytes([1; 32]).unwrap();
114    ///     let es = ElligatorSwift::from_seckey(sk, None);
115    /// # }
116    /// ```
117    pub fn from_seckey(sk: SecretKey, aux_rand: Option<[u8; 32]>) -> ElligatorSwift {
118        let mut es_out = [0u8; constants::ELLSWIFT_ENCODING_SIZE];
119        let aux_rand_ptr = aux_rand.as_c_ptr();
120        unsafe {
121            let ret = crate::with_global_context(
122                |secp: &Secp256k1<crate::AllPreallocated>| {
123                    ffi::secp256k1_ellswift_create(
124                        secp.ctx().as_ptr(),
125                        es_out.as_mut_c_ptr(),
126                        sk.as_c_ptr(),
127                        aux_rand_ptr,
128                    )
129                },
130                Some(&sk.to_secret_bytes()),
131            );
132            debug_assert_eq!(ret, 1);
133        }
134        ElligatorSwift(ffi::ElligatorSwift::from_array(es_out))
135    }
136
137    /// Computes the `ElligatorSwift` encoding for a valid public key
138    /// # Example
139    /// ```
140    /// # #[cfg(feature = "alloc")] {
141    ///     use secp256k1::{ellswift::ElligatorSwift, PublicKey, SecretKey};
142    ///     let sk = SecretKey::from_secret_bytes([1; 32]).unwrap();
143    ///     let pk = PublicKey::from_secret_key(&sk);
144    ///     let es = ElligatorSwift::from_pubkey(pk);
145    /// # }
146    ///
147    /// ```
148    pub fn from_pubkey(pk: PublicKey) -> ElligatorSwift { Self::encode(pk) }
149
150    /// Computes a shared secret only known by Alice and Bob. This is obtained by computing
151    /// the x-only Elliptic Curve Diffie-Hellman (ECDH) shared secret between Alice and Bob.
152    /// # Example
153    /// ```
154    /// # #[cfg(feature = "alloc")] {
155    ///     use secp256k1::{
156    ///         ellswift::{ElligatorSwift, Party},
157    ///         PublicKey, SecretKey, XOnlyPublicKey,
158    ///     };
159    ///     use core::str::FromStr;
160    ///
161    ///     let alice_sk = SecretKey::from_str("e714e76bdd67ad9f495683c37934148f4efc25ce3f01652c8a906498339e1f3a").unwrap();
162    ///     let bob_sk = SecretKey::from_str("b6c4b0e2f8c4359caf356a618cd1649d18790a1d67f7c2d1e4760e04c785db4f").unwrap();
163    ///
164    ///     let alice_es = ElligatorSwift::from_seckey(alice_sk, None);
165    ///     let bob_es = ElligatorSwift::from_seckey(bob_sk, None);
166    ///
167    ///     let alice_shared_secret = ElligatorSwift::shared_secret(alice_es, bob_es, alice_sk, Party::Initiator);
168    ///     let bob_shared_secret = ElligatorSwift::shared_secret(alice_es, bob_es, bob_sk, Party::Responder);
169    ///
170    ///     assert_eq!(alice_shared_secret, bob_shared_secret);
171    /// # }
172    /// ```
173    pub fn shared_secret(
174        ellswift_a: ElligatorSwift,
175        ellswift_b: ElligatorSwift,
176        secret_key: SecretKey,
177        party: impl Into<Party>,
178    ) -> ElligatorSwiftSharedSecret {
179        let mut shared_secret = [0u8; 32];
180        let p: Party = party.into();
181        unsafe {
182            let ret = ffi::secp256k1_ellswift_xdh(
183                ffi::secp256k1_context_no_precomp,
184                shared_secret.as_mut_c_ptr(),
185                ellswift_a.as_c_ptr(),
186                ellswift_b.as_c_ptr(),
187                secret_key.as_c_ptr(),
188                p.to_ffi_int(),
189                ffi::secp256k1_ellswift_xdh_hash_function_bip324,
190                ptr::null_mut(),
191            );
192            debug_assert_eq!(ret, 1);
193        }
194        ElligatorSwiftSharedSecret(shared_secret)
195    }
196
197    /// Computes a shared secret, just like `shared_secret`, but with a custom hash function
198    /// for computing the shared secret. For compatibility with other libraries, you should
199    /// use `shared_secret` instead, which is already compatible with BIP324.
200    /// The hash function takes three arguments: the shared point, and the `ElligatorSwift`
201    /// encodings of the two parties and returns a 32-byte shared secret.
202    pub fn shared_secret_with_hasher<F>(
203        ellswift_a: ElligatorSwift,
204        ellswift_b: ElligatorSwift,
205        secret_key: SecretKey,
206        party: impl Into<Party>,
207        mut hash_function: F,
208    ) -> ElligatorSwiftSharedSecret
209    where
210        F: FnMut([u8; 32], [u8; 64], [u8; 64]) -> ElligatorSwiftSharedSecret,
211    {
212        let mut shared_secret = [0u8; 32];
213        let hashfp = hash_callback::<F>;
214        let p: Party = party.into();
215        unsafe {
216            let ret = ffi::secp256k1_ellswift_xdh(
217                ffi::secp256k1_context_no_precomp,
218                shared_secret.as_mut_c_ptr(),
219                ellswift_a.0.as_c_ptr(),
220                ellswift_b.0.as_c_ptr(),
221                secret_key.as_c_ptr(),
222                p.to_ffi_int(),
223                Some(hashfp),
224                &mut hash_function as *mut F as *mut c_void,
225            );
226            debug_assert_eq!(ret, 1);
227        }
228        ElligatorSwiftSharedSecret(shared_secret)
229    }
230
231    /// Encodes a public key into an `ElligatorSwift` encoding
232    fn encode(pk: PublicKey) -> ElligatorSwift {
233        let mut ell_out = [0u8; constants::ELLSWIFT_ENCODING_SIZE];
234        unsafe {
235            let ret = ffi::secp256k1_ellswift_encode(
236                ffi::secp256k1_context_no_precomp,
237                ell_out.as_mut_c_ptr(),
238                pk.as_c_ptr(),
239                [0u8; 32].as_ptr(),
240            );
241            debug_assert_eq!(ret, 1);
242        }
243        ElligatorSwift(ffi::ElligatorSwift::from_array(ell_out))
244    }
245
246    /// Decodes an `ElligatorSwift` encoding into a [`PublicKey`].
247    pub(crate) fn decode(ell: ElligatorSwift) -> PublicKey {
248        unsafe {
249            let mut pk = ffi::PublicKey::new();
250
251            let ret = ffi::secp256k1_ellswift_decode(
252                ffi::secp256k1_context_no_precomp,
253                pk.as_mut_c_ptr(),
254                ell.as_c_ptr(),
255            );
256            debug_assert_eq!(ret, 1);
257            PublicKey::from(pk)
258        }
259    }
260}
261
262/// The result of `ElligatorSwift::shared_secret`, which is a shared secret
263/// computed from the x-only ECDH using both parties' public keys (`ElligatorSwift` encoded) and our own
264/// private key.
265#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
266pub struct ElligatorSwiftSharedSecret([u8; 32]);
267
268impl ElligatorSwiftSharedSecret {
269    /// Creates shared secret from bytes.
270    ///
271    /// This is generally not needed except for unusual cases like restoring the secret from a
272    /// database.
273    pub const fn from_secret_bytes(bytes: [u8; 32]) -> Self { Self(bytes) }
274
275    /// Returns the secret bytes as an array.
276    pub const fn to_secret_bytes(self) -> [u8; 32] { self.0 }
277
278    /// Returns the secret bytes as a reference to an array.
279    pub const fn as_secret_bytes(&self) -> &[u8; 32] { &self.0 }
280}
281
282/// Represents the two parties in ECDH
283#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
284pub enum Party {
285    /// The party that starts the key exchange or communication process
286    Initiator,
287    /// The party that responds to the initiator's communications
288    Responder,
289}
290
291impl Party {
292    fn to_ffi_int(self) -> c_int {
293        match self {
294            Party::Initiator => 0,
295            Party::Responder => 1,
296        }
297    }
298}
299
300impl FromStr for ElligatorSwift {
301    fn from_str(hex: &str) -> Result<Self, Self::Err> {
302        let mut ser = [0u8; 64];
303        let parsed = from_hex(hex, &mut ser);
304        match parsed {
305            Ok(64) => Ok(ElligatorSwift::from_array(ser)),
306            _ => Err(Error::InvalidEllSwift),
307        }
308    }
309    type Err = Error;
310}
311
312impl fmt::LowerHex for ElligatorSwift {
313    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
314        let ser = self.to_array();
315        for ch in ser.iter() {
316            write!(f, "{:02x}", ch)?;
317        }
318        Ok(())
319    }
320}
321
322impl Display for ElligatorSwift {
323    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { core::fmt::LowerHex::fmt(&self, f) }
324}
325
326impl ffi::CPtr for ElligatorSwift {
327    type Target = u8;
328    fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.0.as_mut_c_ptr() }
329    fn as_c_ptr(&self) -> *const Self::Target { self.0.as_c_ptr() }
330}
331
332#[cfg(test)]
333mod tests {
334    use core::str::FromStr;
335
336    use crate::ellswift::ElligatorSwift;
337    #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))]
338    use crate::ellswift::{ElligatorSwiftSharedSecret, Party};
339    #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))]
340    use crate::SecretKey;
341    use crate::{from_hex, PublicKey, XOnlyPublicKey};
342
343    #[test]
344    #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))]
345    fn test_elligator_swift_rtt() {
346        // Test that we can round trip an ElligatorSwift encoding
347        let public_key =
348            PublicKey::from_secret_key(&SecretKey::from_secret_bytes([1u8; 32]).unwrap());
349
350        let ell = ElligatorSwift::from_pubkey(public_key);
351        let pk = PublicKey::from_ellswift(ell);
352        assert_eq!(pk, public_key);
353    }
354    #[test]
355    #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))]
356    fn test_create_elligator_swift_create_rtt() {
357        // Test that we can round trip an ElligatorSwift created from a secret key
358        let rand32 = [1u8; 32];
359        let priv32 = [1u8; 32];
360        let ell = ElligatorSwift::from_seckey(SecretKey::from_secret_bytes(rand32).unwrap(), None);
361        let pk = PublicKey::from_ellswift(ell);
362        let expected = PublicKey::from_secret_key(&SecretKey::from_secret_bytes(priv32).unwrap());
363
364        assert_eq!(pk, expected);
365    }
366    #[test]
367    #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))]
368    fn test_xdh_with_custom_hasher() {
369        // Test the ECDH with a custom hash function
370        let rand32 = [1u8; 32];
371        let priv32 = [2u8; 32];
372        let ell = ElligatorSwift::from_seckey(
373            SecretKey::from_secret_bytes(rand32).unwrap(),
374            Some(rand32),
375        );
376        let pk = ElligatorSwift::shared_secret_with_hasher(
377            ell,
378            ell,
379            SecretKey::from_secret_bytes(priv32).unwrap(),
380            Party::Initiator,
381            |_, _, _| ElligatorSwiftSharedSecret([0xff; 32]),
382        );
383        assert_eq!(pk, ElligatorSwiftSharedSecret([0xff; 32]));
384    }
385    #[test]
386    #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))]
387    fn ellswift_ecdh_test() {
388        let tests = vec![
389            (
390                [
391                    0x61, 0x06, 0x2e, 0xa5, 0x07, 0x1d, 0x80, 0x0b, 0xbf, 0xd5, 0x9e, 0x2e, 0x8b,
392                    0x53, 0xd4, 0x7d, 0x19, 0x4b, 0x09, 0x5a, 0xe5, 0xa4, 0xdf, 0x04, 0x93, 0x6b,
393                    0x49, 0x77, 0x2e, 0xf0, 0xd4, 0xd7,
394                ],
395                [
396                    0xec, 0x0a, 0xdf, 0xf2, 0x57, 0xbb, 0xfe, 0x50, 0x0c, 0x18, 0x8c, 0x80, 0xb4,
397                    0xfd, 0xd6, 0x40, 0xf6, 0xb4, 0x5a, 0x48, 0x2b, 0xbc, 0x15, 0xfc, 0x7c, 0xef,
398                    0x59, 0x31, 0xde, 0xff, 0x0a, 0xa1, 0x86, 0xf6, 0xeb, 0x9b, 0xba, 0x7b, 0x85,
399                    0xdc, 0x4d, 0xcc, 0x28, 0xb2, 0x87, 0x22, 0xde, 0x1e, 0x3d, 0x91, 0x08, 0xb9,
400                    0x85, 0xe2, 0x96, 0x70, 0x45, 0x66, 0x8f, 0x66, 0x09, 0x8e, 0x47, 0x5b,
401                ],
402                [
403                    0xa4, 0xa9, 0x4d, 0xfc, 0xe6, 0x9b, 0x4a, 0x2a, 0x0a, 0x09, 0x93, 0x13, 0xd1,
404                    0x0f, 0x9f, 0x7e, 0x7d, 0x64, 0x9d, 0x60, 0x50, 0x1c, 0x9e, 0x1d, 0x27, 0x4c,
405                    0x30, 0x0e, 0x0d, 0x89, 0xaa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
406                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
407                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xaf, 0x88, 0xd5,
408                ],
409                1,
410                [
411                    0xc6, 0x99, 0x2a, 0x11, 0x7f, 0x5e, 0xdb, 0xea, 0x70, 0xc3, 0xf5, 0x11, 0xd3,
412                    0x2d, 0x26, 0xb9, 0x79, 0x8b, 0xe4, 0xb8, 0x1a, 0x62, 0xea, 0xee, 0x1a, 0x5a,
413                    0xca, 0xa8, 0x45, 0x9a, 0x35, 0x92,
414                ],
415            ),
416            (
417                [
418                    0x1f, 0x9c, 0x58, 0x1b, 0x35, 0x23, 0x18, 0x38, 0xf0, 0xf1, 0x7c, 0xf0, 0xc9,
419                    0x79, 0x83, 0x5b, 0xac, 0xcb, 0x7f, 0x3a, 0xbb, 0xbb, 0x96, 0xff, 0xcc, 0x31,
420                    0x8a, 0xb7, 0x1e, 0x6e, 0x12, 0x6f,
421                ],
422                [
423                    0xa1, 0x85, 0x5e, 0x10, 0xe9, 0x4e, 0x00, 0xba, 0xa2, 0x30, 0x41, 0xd9, 0x16,
424                    0xe2, 0x59, 0xf7, 0x04, 0x4e, 0x49, 0x1d, 0xa6, 0x17, 0x12, 0x69, 0x69, 0x47,
425                    0x63, 0xf0, 0x18, 0xc7, 0xe6, 0x36, 0x93, 0xd2, 0x95, 0x75, 0xdc, 0xb4, 0x64,
426                    0xac, 0x81, 0x6b, 0xaa, 0x1b, 0xe3, 0x53, 0xba, 0x12, 0xe3, 0x87, 0x6c, 0xba,
427                    0x76, 0x28, 0xbd, 0x0b, 0xd8, 0xe7, 0x55, 0xe7, 0x21, 0xeb, 0x01, 0x40,
428                ],
429                [
430                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
431                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
432                    0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
433                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
434                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
435                ],
436                0,
437                [
438                    0xa0, 0x13, 0x8f, 0x56, 0x4f, 0x74, 0xd0, 0xad, 0x70, 0xbc, 0x33, 0x7d, 0xac,
439                    0xc9, 0xd0, 0xbf, 0x1d, 0x23, 0x49, 0x36, 0x4c, 0xaf, 0x11, 0x88, 0xa1, 0xe6,
440                    0xe8, 0xdd, 0xb3, 0xb7, 0xb1, 0x84,
441                ],
442            ),
443            (
444                [
445                    0x02, 0x86, 0xc4, 0x1c, 0xd3, 0x09, 0x13, 0xdb, 0x0f, 0xdf, 0xf7, 0xa6, 0x4e,
446                    0xbd, 0xa5, 0xc8, 0xe3, 0xe7, 0xce, 0xf1, 0x0f, 0x2a, 0xeb, 0xc0, 0x0a, 0x76,
447                    0x50, 0x44, 0x3c, 0xf4, 0xc6, 0x0d,
448                ],
449                [
450                    0xd1, 0xee, 0x8a, 0x93, 0xa0, 0x11, 0x30, 0xcb, 0xf2, 0x99, 0x24, 0x9a, 0x25,
451                    0x8f, 0x94, 0xfe, 0xb5, 0xf4, 0x69, 0xe7, 0xd0, 0xf2, 0xf2, 0x8f, 0x69, 0xee,
452                    0x5e, 0x9a, 0xa8, 0xf9, 0xb5, 0x4a, 0x60, 0xf2, 0xc3, 0xff, 0x2d, 0x02, 0x36,
453                    0x34, 0xec, 0x7f, 0x41, 0x27, 0xa9, 0x6c, 0xc1, 0x16, 0x62, 0xe4, 0x02, 0x89,
454                    0x4c, 0xf1, 0xf6, 0x94, 0xfb, 0x9a, 0x7e, 0xaa, 0x5f, 0x1d, 0x92, 0x44,
455                ],
456                [
457                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
458                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
459                    0xff, 0xff, 0x22, 0xd5, 0xe4, 0x41, 0x52, 0x4d, 0x57, 0x1a, 0x52, 0xb3, 0xde,
460                    0xf1, 0x26, 0x18, 0x9d, 0x3f, 0x41, 0x68, 0x90, 0xa9, 0x9d, 0x4d, 0xa6, 0xed,
461                    0xe2, 0xb0, 0xcd, 0xe1, 0x76, 0x0c, 0xe2, 0xc3, 0xf9, 0x84, 0x57, 0xae,
462                ],
463                1,
464                [
465                    0x25, 0x0b, 0x93, 0x57, 0x0d, 0x41, 0x11, 0x49, 0x10, 0x5a, 0xb8, 0xcb, 0x0b,
466                    0xc5, 0x07, 0x99, 0x14, 0x90, 0x63, 0x06, 0x36, 0x8c, 0x23, 0xe9, 0xd7, 0x7c,
467                    0x2a, 0x33, 0x26, 0x5b, 0x99, 0x4c,
468                ],
469            ),
470            (
471                [
472                    0x6c, 0x77, 0x43, 0x2d, 0x1f, 0xda, 0x31, 0xe9, 0xf9, 0x42, 0xf8, 0xaf, 0x44,
473                    0x60, 0x7e, 0x10, 0xf3, 0xad, 0x38, 0xa6, 0x5f, 0x8a, 0x4b, 0xdd, 0xae, 0x82,
474                    0x3e, 0x5e, 0xff, 0x90, 0xdc, 0x38,
475                ],
476                [
477                    0xd2, 0x68, 0x50, 0x70, 0xc1, 0xe6, 0x37, 0x6e, 0x63, 0x3e, 0x82, 0x52, 0x96,
478                    0x63, 0x4f, 0xd4, 0x61, 0xfa, 0x9e, 0x5b, 0xdf, 0x21, 0x09, 0xbc, 0xeb, 0xd7,
479                    0x35, 0xe5, 0xa9, 0x1f, 0x3e, 0x58, 0x7c, 0x5c, 0xb7, 0x82, 0xab, 0xb7, 0x97,
480                    0xfb, 0xf6, 0xbb, 0x50, 0x74, 0xfd, 0x15, 0x42, 0xa4, 0x74, 0xf2, 0xa4, 0x5b,
481                    0x67, 0x37, 0x63, 0xec, 0x2d, 0xb7, 0xfb, 0x99, 0xb7, 0x37, 0xbb, 0xb9,
482                ],
483                [
484                    0x56, 0xbd, 0x0c, 0x06, 0xf1, 0x03, 0x52, 0xc3, 0xa1, 0xa9, 0xf4, 0xb4, 0xc9,
485                    0x2f, 0x6f, 0xa2, 0xb2, 0x6d, 0xf1, 0x24, 0xb5, 0x78, 0x78, 0x35, 0x3c, 0x1f,
486                    0xc6, 0x91, 0xc5, 0x1a, 0xbe, 0xa7, 0x7c, 0x88, 0x17, 0xda, 0xee, 0xb9, 0xfa,
487                    0x54, 0x6b, 0x77, 0xc8, 0xda, 0xf7, 0x9d, 0x89, 0xb2, 0x2b, 0x0e, 0x1b, 0x87,
488                    0x57, 0x4e, 0xce, 0x42, 0x37, 0x1f, 0x00, 0x23, 0x7a, 0xa9, 0xd8, 0x3a,
489                ],
490                0,
491                [
492                    0x19, 0x18, 0xb7, 0x41, 0xef, 0x5f, 0x9d, 0x1d, 0x76, 0x70, 0xb0, 0x50, 0xc1,
493                    0x52, 0xb4, 0xa4, 0xea, 0xd2, 0xc3, 0x1b, 0xe9, 0xae, 0xcb, 0x06, 0x81, 0xc0,
494                    0xcd, 0x43, 0x24, 0x15, 0x08, 0x53,
495                ],
496            ),
497            (
498                [
499                    0xa6, 0xec, 0x25, 0x12, 0x7c, 0xa1, 0xaa, 0x4c, 0xf1, 0x6b, 0x20, 0x08, 0x4b,
500                    0xa1, 0xe6, 0x51, 0x6b, 0xaa, 0xe4, 0xd3, 0x24, 0x22, 0x28, 0x8e, 0x9b, 0x36,
501                    0xd8, 0xbd, 0xdd, 0x2d, 0xe3, 0x5a,
502                ],
503                [
504                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
505                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
506                    0xff, 0xff, 0x05, 0x3d, 0x7e, 0xcc, 0xa5, 0x3e, 0x33, 0xe1, 0x85, 0xa8, 0xb9,
507                    0xbe, 0x4e, 0x76, 0x99, 0xa9, 0x7c, 0x6f, 0xf4, 0xc7, 0x95, 0x52, 0x2e, 0x59,
508                    0x18, 0xab, 0x7c, 0xd6, 0xb6, 0x88, 0x4f, 0x67, 0xe6, 0x83, 0xf3, 0xdc,
509                ],
510                [
511                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
512                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
513                    0xff, 0xff, 0xa7, 0x73, 0x0b, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
514                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
515                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
516                ],
517                1,
518                [
519                    0xdd, 0x21, 0x0a, 0xa6, 0x62, 0x9f, 0x20, 0xbb, 0x32, 0x8e, 0x5d, 0x89, 0xda,
520                    0xa6, 0xeb, 0x2a, 0xc3, 0xd1, 0xc6, 0x58, 0xa7, 0x25, 0x53, 0x6f, 0xf1, 0x54,
521                    0xf3, 0x1b, 0x53, 0x6c, 0x23, 0xb2,
522                ],
523            ),
524            (
525                [
526                    0x0a, 0xf9, 0x52, 0x65, 0x9e, 0xd7, 0x6f, 0x80, 0xf5, 0x85, 0x96, 0x6b, 0x95,
527                    0xab, 0x6e, 0x6f, 0xd6, 0x86, 0x54, 0x67, 0x28, 0x27, 0x87, 0x86, 0x84, 0xc8,
528                    0xb5, 0x47, 0xb1, 0xb9, 0x4f, 0x5a,
529                ],
530                [
531                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
532                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
533                    0xff, 0xff, 0xc8, 0x10, 0x17, 0xfd, 0x92, 0xfd, 0x31, 0x63, 0x7c, 0x26, 0xc9,
534                    0x06, 0xb4, 0x20, 0x92, 0xe1, 0x1c, 0xc0, 0xd3, 0xaf, 0xae, 0x8d, 0x90, 0x19,
535                    0xd2, 0x57, 0x8a, 0xf2, 0x27, 0x35, 0xce, 0x7b, 0xc4, 0x69, 0xc7, 0x2d,
536                ],
537                [
538                    0x96, 0x52, 0xd7, 0x8b, 0xae, 0xfc, 0x02, 0x8c, 0xd3, 0x7a, 0x6a, 0x92, 0x62,
539                    0x5b, 0x8b, 0x8f, 0x85, 0xfd, 0xe1, 0xe4, 0xc9, 0x44, 0xad, 0x3f, 0x20, 0xe1,
540                    0x98, 0xbe, 0xf8, 0xc0, 0x2f, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
541                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
542                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf2, 0xe9, 0x18, 0x70,
543                ],
544                0,
545                [
546                    0x35, 0x68, 0xf2, 0xae, 0xa2, 0xe1, 0x4e, 0xf4, 0xee, 0x4a, 0x3c, 0x2a, 0x8b,
547                    0x8d, 0x31, 0xbc, 0x5e, 0x31, 0x87, 0xba, 0x86, 0xdb, 0x10, 0x73, 0x9b, 0x4f,
548                    0xf8, 0xec, 0x92, 0xff, 0x66, 0x55,
549                ],
550            ),
551            (
552                [
553                    0xf9, 0x0e, 0x08, 0x0c, 0x64, 0xb0, 0x58, 0x24, 0xc5, 0xa2, 0x4b, 0x25, 0x01,
554                    0xd5, 0xae, 0xaf, 0x08, 0xaf, 0x38, 0x72, 0xee, 0x86, 0x0a, 0xa8, 0x0b, 0xdc,
555                    0xd4, 0x30, 0xf7, 0xb6, 0x34, 0x94,
556                ],
557                [
558                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
559                    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
560                    0xff, 0xff, 0x11, 0x51, 0x73, 0x76, 0x5d, 0xc2, 0x02, 0xcf, 0x02, 0x9a, 0xd3,
561                    0xf1, 0x54, 0x79, 0x73, 0x5d, 0x57, 0x69, 0x7a, 0xf1, 0x2b, 0x01, 0x31, 0xdd,
562                    0x21, 0x43, 0x0d, 0x57, 0x72, 0xe4, 0xef, 0x11, 0x47, 0x4d, 0x58, 0xb9,
563                ],
564                [
565                    0x12, 0xa5, 0x0f, 0x3f, 0xaf, 0xea, 0x7c, 0x1e, 0xea, 0xda, 0x4c, 0xf8, 0xd3,
566                    0x37, 0x77, 0x70, 0x4b, 0x77, 0x36, 0x14, 0x53, 0xaf, 0xc8, 0x3b, 0xda, 0x91,
567                    0xee, 0xf3, 0x49, 0xae, 0x04, 0x4d, 0x20, 0x12, 0x6c, 0x62, 0x00, 0x54, 0x7e,
568                    0xa5, 0xa6, 0x91, 0x17, 0x76, 0xc0, 0x5d, 0xee, 0x2a, 0x7f, 0x1a, 0x9b, 0xa7,
569                    0xdf, 0xba, 0xbb, 0xbd, 0x27, 0x3c, 0x3e, 0xf2, 0x9e, 0xf4, 0x6e, 0x46,
570                ],
571                1,
572                [
573                    0xe2, 0x54, 0x61, 0xfb, 0x0e, 0x4c, 0x16, 0x2e, 0x18, 0x12, 0x3e, 0xcd, 0xe8,
574                    0x83, 0x42, 0xd5, 0x4d, 0x44, 0x96, 0x31, 0xe9, 0xb7, 0x5a, 0x26, 0x6f, 0xd9,
575                    0x26, 0x0c, 0x2b, 0xb2, 0xf4, 0x1d,
576                ],
577            ),
578        ];
579        for (my_secret, ellswift_ours, ellswift_theirs, initiator, shared_secret) in tests {
580            // We are not the initiator, so we are B
581            let (el_a, el_b) = if initiator == 0 {
582                (
583                    ElligatorSwift::from_array(ellswift_theirs),
584                    ElligatorSwift::from_array(ellswift_ours),
585                )
586            } else {
587                // We are the initiator, so we are A
588                (
589                    ElligatorSwift::from_array(ellswift_ours),
590                    ElligatorSwift::from_array(ellswift_theirs),
591                )
592            };
593            let sec_key = SecretKey::from_secret_bytes(my_secret).unwrap();
594            let initiator = if initiator == 0 { Party::Responder } else { Party::Initiator };
595
596            let shared = ElligatorSwift::shared_secret(el_a, el_b, sec_key, initiator);
597
598            assert_eq!(shared.0, shared_secret);
599        }
600    }
601    #[test]
602    #[cfg(not(secp256k1_fuzz))]
603    fn ellswift_decode_test() {
604        struct EllswiftDecodeTest {
605            enc: [u8; 64],
606            key: PublicKey,
607        }
608        #[inline]
609        fn parse_test(ell: &str, x: &str, parity: u32) -> EllswiftDecodeTest {
610            let mut enc = [0u8; 64];
611            from_hex(ell, &mut enc).unwrap();
612            let xo = XOnlyPublicKey::from_str(x).unwrap();
613            let parity = if parity == 0 { crate::Parity::Even } else { crate::Parity::Odd };
614            let pk = PublicKey::from_x_only_public_key(xo, parity);
615            EllswiftDecodeTest { enc, key: pk }
616        }
617        macro_rules! make_tests {
618            ($(($ell: literal, $x: literal, $parity: literal)),+) => {
619                [$(
620                    parse_test($ell, $x, $parity),
621                )+]
622            };
623        }
624        let tests = make_tests!(
625            ("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","edd1fd3e327ce90cc7a3542614289aee9682003e9cf7dcc9cf2ca9743be5aa0c", 0),
626            ("000000000000000000000000000000000000000000000000000000000000000001d3475bf7655b0fb2d852921035b2ef607f49069b97454e6795251062741771","b5da00b73cd6560520e7c364086e7cd23a34bf60d0e707be9fc34d4cd5fdfa2c", 1),
627            ("000000000000000000000000000000000000000000000000000000000000000082277c4a71f9d22e66ece523f8fa08741a7c0912c66a69ce68514bfd3515b49f","f482f2e241753ad0fb89150d8491dc1e34ff0b8acfbb442cfe999e2e5e6fd1d2", 1),
628            ("00000000000000000000000000000000000000000000000000000000000000008421cc930e77c9f514b6915c3dbe2a94c6d8f690b5b739864ba6789fb8a55dd0","9f59c40275f5085a006f05dae77eb98c6fd0db1ab4a72ac47eae90a4fc9e57e0", 0),
629            ("0000000000000000000000000000000000000000000000000000000000000000bde70df51939b94c9c24979fa7dd04ebd9b3572da7802290438af2a681895441","aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9fffffd6b", 1),
630            ("0000000000000000000000000000000000000000000000000000000000000000d19c182d2759cd99824228d94799f8c6557c38a1c0d6779b9d4b729c6f1ccc42","70720db7e238d04121f5b1afd8cc5ad9d18944c6bdc94881f502b7a3af3aecff", 0),
631            ("0000000000000000000000000000000000000000000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","edd1fd3e327ce90cc7a3542614289aee9682003e9cf7dcc9cf2ca9743be5aa0c", 0),
632            ("0000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff2664bbd5","50873db31badcc71890e4f67753a65757f97aaa7dd5f1e82b753ace32219064b", 0),
633            ("0000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff7028de7d","1eea9cc59cfcf2fa151ac6c274eea4110feb4f7b68c5965732e9992e976ef68e", 0),
634            ("0000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffcbcfb7e7","12303941aedc208880735b1f1795c8e55be520ea93e103357b5d2adb7ed59b8e", 0),
635            ("0000000000000000000000000000000000000000000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffff3113ad9","7eed6b70e7b0767c7d7feac04e57aa2a12fef5e0f48f878fcbb88b3b6b5e0783", 0),
636            ("0a2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f8530000000000000000000000000000000000000000000000000000000000000000","532167c11200b08c0e84a354e74dcc40f8b25f4fe686e30869526366278a0688", 0),
637            ("0a2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f853fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","532167c11200b08c0e84a354e74dcc40f8b25f4fe686e30869526366278a0688", 0),
638            ("0ffde9ca81d751e9cdaffc1a50779245320b28996dbaf32f822f20117c22fbd6c74d99efceaa550f1ad1c0f43f46e7ff1ee3bd0162b7bf55f2965da9c3450646","74e880b3ffd18fe3cddf7902522551ddf97fa4a35a3cfda8197f947081a57b8f", 0),
639            ("0ffde9ca81d751e9cdaffc1a50779245320b28996dbaf32f822f20117c22fbd6ffffffffffffffffffffffffffffffffffffffffffffffffffffffff156ca896","377b643fce2271f64e5c8101566107c1be4980745091783804f654781ac9217c", 1),
640            ("123658444f32be8f02ea2034afa7ef4bbe8adc918ceb49b12773b625f490b368ffffffffffffffffffffffffffffffffffffffffffffffffffffffff8dc5fe11","ed16d65cf3a9538fcb2c139f1ecbc143ee14827120cbc2659e667256800b8142", 0),
641            ("146f92464d15d36e35382bd3ca5b0f976c95cb08acdcf2d5b3570617990839d7ffffffffffffffffffffffffffffffffffffffffffffffffffffffff3145e93b","0d5cd840427f941f65193079ab8e2e83024ef2ee7ca558d88879ffd879fb6657", 0),
642            ("15fdf5cf09c90759add2272d574d2bb5fe1429f9f3c14c65e3194bf61b82aa73ffffffffffffffffffffffffffffffffffffffffffffffffffffffff04cfd906","16d0e43946aec93f62d57eb8cde68951af136cf4b307938dd1447411e07bffe1", 1),
643            ("1f67edf779a8a649d6def60035f2fa22d022dd359079a1a144073d84f19b92d50000000000000000000000000000000000000000000000000000000000000000","025661f9aba9d15c3118456bbe980e3e1b8ba2e047c737a4eb48a040bb566f6c", 0),
644            ("1f67edf779a8a649d6def60035f2fa22d022dd359079a1a144073d84f19b92d5fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","025661f9aba9d15c3118456bbe980e3e1b8ba2e047c737a4eb48a040bb566f6c", 0),
645            ("1fe1e5ef3fceb5c135ab7741333ce5a6e80d68167653f6b2b24bcbcfaaaff507fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","98bec3b2a351fa96cfd191c1778351931b9e9ba9ad1149f6d9eadca80981b801", 0),
646            ("4056a34a210eec7892e8820675c860099f857b26aad85470ee6d3cf1304a9dcf375e70374271f20b13c9986ed7d3c17799698cfc435dbed3a9f34b38c823c2b4","868aac2003b29dbcad1a3e803855e078a89d16543ac64392d122417298cec76e", 0),
647            ("4197ec3723c654cfdd32ab075506648b2ff5070362d01a4fff14b336b78f963fffffffffffffffffffffffffffffffffffffffffffffffffffffffffb3ab1e95","ba5a6314502a8952b8f456e085928105f665377a8ce27726a5b0eb7ec1ac0286", 0),
648            ("47eb3e208fedcdf8234c9421e9cd9a7ae873bfbdbc393723d1ba1e1e6a8e6b24ffffffffffffffffffffffffffffffffffffffffffffffffffffffff7cd12cb1","d192d52007e541c9807006ed0468df77fd214af0a795fe119359666fdcf08f7c", 0),
649            ("5eb9696a2336fe2c3c666b02c755db4c0cfd62825c7b589a7b7bb442e141c1d693413f0052d49e64abec6d5831d66c43612830a17df1fe4383db896468100221","ef6e1da6d6c7627e80f7a7234cb08a022c1ee1cf29e4d0f9642ae924cef9eb38", 1),
650            ("7bf96b7b6da15d3476a2b195934b690a3a3de3e8ab8474856863b0de3af90b0e0000000000000000000000000000000000000000000000000000000000000000","50851dfc9f418c314a437295b24feeea27af3d0cd2308348fda6e21c463e46ff", 0),
651            ("7bf96b7b6da15d3476a2b195934b690a3a3de3e8ab8474856863b0de3af90b0efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","50851dfc9f418c314a437295b24feeea27af3d0cd2308348fda6e21c463e46ff", 0),
652            ("851b1ca94549371c4f1f7187321d39bf51c6b7fb61f7cbf027c9da62021b7a65fc54c96837fb22b362eda63ec52ec83d81bedd160c11b22d965d9f4a6d64d251","3e731051e12d33237eb324f2aa5b16bb868eb49a1aa1fadc19b6e8761b5a5f7b", 1),
653            ("943c2f775108b737fe65a9531e19f2fc2a197f5603e3a2881d1d83e4008f91250000000000000000000000000000000000000000000000000000000000000000","311c61f0ab2f32b7b1f0223fa72f0a78752b8146e46107f8876dd9c4f92b2942", 0),
654            ("943c2f775108b737fe65a9531e19f2fc2a197f5603e3a2881d1d83e4008f9125fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","311c61f0ab2f32b7b1f0223fa72f0a78752b8146e46107f8876dd9c4f92b2942", 0),
655            ("a0f18492183e61e8063e573606591421b06bc3513631578a73a39c1c3306239f2f32904f0d2a33ecca8a5451705bb537d3bf44e071226025cdbfd249fe0f7ad6","97a09cf1a2eae7c494df3c6f8a9445bfb8c09d60832f9b0b9d5eabe25fbd14b9", 0),
656            ("a1ed0a0bd79d8a23cfe4ec5fef5ba5cccfd844e4ff5cb4b0f2e71627341f1c5b17c499249e0ac08d5d11ea1c2c8ca7001616559a7994eadec9ca10fb4b8516dc","65a89640744192cdac64b2d21ddf989cdac7500725b645bef8e2200ae39691f2", 0),
657            ("ba94594a432721aa3580b84c161d0d134bc354b690404d7cd4ec57c16d3fbe98ffffffffffffffffffffffffffffffffffffffffffffffffffffffffea507dd7","5e0d76564aae92cb347e01a62afd389a9aa401c76c8dd227543dc9cd0efe685a", 0),
658            ("bcaf7219f2f6fbf55fe5e062dce0e48c18f68103f10b8198e974c184750e1be3932016cbf69c4471bd1f656c6a107f1973de4af7086db897277060e25677f19a","2d97f96cac882dfe73dc44db6ce0f1d31d6241358dd5d74eb3d3b50003d24c2b", 0),
659            ("bcaf7219f2f6fbf55fe5e062dce0e48c18f68103f10b8198e974c184750e1be3ffffffffffffffffffffffffffffffffffffffffffffffffffffffff6507d09a","e7008afe6e8cbd5055df120bd748757c686dadb41cce75e4addcc5e02ec02b44", 1),
660            ("c5981bae27fd84401c72a155e5707fbb811b2b620645d1028ea270cbe0ee225d4b62aa4dca6506c1acdbecc0552569b4b21436a5692e25d90d3bc2eb7ce24078","948b40e7181713bc018ec1702d3d054d15746c59a7020730dd13ecf985a010d7", 0),
661            ("c894ce48bfec433014b931a6ad4226d7dbd8eaa7b6e3faa8d0ef94052bcf8cff336eeb3919e2b4efb746c7f71bbca7e9383230fbbc48ffafe77e8bcc69542471","f1c91acdc2525330f9b53158434a4d43a1c547cff29f15506f5da4eb4fe8fa5a", 1),
662            ("cbb0deab125754f1fdb2038b0434ed9cb3fb53ab735391129994a535d925f6730000000000000000000000000000000000000000000000000000000000000000","872d81ed8831d9998b67cb7105243edbf86c10edfebb786c110b02d07b2e67cd", 0),
663            ("d917b786dac35670c330c9c5ae5971dfb495c8ae523ed97ee2420117b171f41effffffffffffffffffffffffffffffffffffffffffffffffffffffff2001f6f6","e45b71e110b831f2bdad8651994526e58393fde4328b1ec04d59897142584691", 1),
664            ("e28bd8f5929b467eb70e04332374ffb7e7180218ad16eaa46b7161aa679eb4260000000000000000000000000000000000000000000000000000000000000000","66b8c980a75c72e598d383a35a62879f844242ad1e73ff12edaa59f4e58632b5", 0),
665            ("e28bd8f5929b467eb70e04332374ffb7e7180218ad16eaa46b7161aa679eb426fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","66b8c980a75c72e598d383a35a62879f844242ad1e73ff12edaa59f4e58632b5", 0),
666            ("e7ee5814c1706bf8a89396a9b032bc014c2cac9c121127dbf6c99278f8bb53d1dfd04dbcda8e352466b6fcd5f2dea3e17d5e133115886eda20db8a12b54de71b","e842c6e3529b234270a5e97744edc34a04d7ba94e44b6d2523c9cf0195730a50", 1),
667            ("f292e46825f9225ad23dc057c1d91c4f57fcb1386f29ef10481cb1d22518593fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7011c989","3cea2c53b8b0170166ac7da67194694adacc84d56389225e330134dab85a4d55", 0),
668            ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f0000000000000000000000000000000000000000000000000000000000000000","edd1fd3e327ce90cc7a3542614289aee9682003e9cf7dcc9cf2ca9743be5aa0c", 0),
669            ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f01d3475bf7655b0fb2d852921035b2ef607f49069b97454e6795251062741771","b5da00b73cd6560520e7c364086e7cd23a34bf60d0e707be9fc34d4cd5fdfa2c", 1),
670            ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f4218f20ae6c646b363db68605822fb14264ca8d2587fdd6fbc750d587e76a7ee","aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9fffffd6b", 0),
671            ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f82277c4a71f9d22e66ece523f8fa08741a7c0912c66a69ce68514bfd3515b49f","f482f2e241753ad0fb89150d8491dc1e34ff0b8acfbb442cfe999e2e5e6fd1d2", 1),
672            ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8421cc930e77c9f514b6915c3dbe2a94c6d8f690b5b739864ba6789fb8a55dd0","9f59c40275f5085a006f05dae77eb98c6fd0db1ab4a72ac47eae90a4fc9e57e0", 0),
673            ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fd19c182d2759cd99824228d94799f8c6557c38a1c0d6779b9d4b729c6f1ccc42","70720db7e238d04121f5b1afd8cc5ad9d18944c6bdc94881f502b7a3af3aecff", 0),
674            ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","edd1fd3e327ce90cc7a3542614289aee9682003e9cf7dcc9cf2ca9743be5aa0c", 0),
675            ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fffffffffffffffffffffffffffffffffffffffffffffffffffffffff2664bbd5","50873db31badcc71890e4f67753a65757f97aaa7dd5f1e82b753ace32219064b", 0),
676            ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7028de7d","1eea9cc59cfcf2fa151ac6c274eea4110feb4f7b68c5965732e9992e976ef68e", 0),
677            ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fffffffffffffffffffffffffffffffffffffffffffffffffffffffffcbcfb7e7","12303941aedc208880735b1f1795c8e55be520ea93e103357b5d2adb7ed59b8e", 0),
678            ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3113ad9","7eed6b70e7b0767c7d7feac04e57aa2a12fef5e0f48f878fcbb88b3b6b5e0783", 0),
679            ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff13cea4a70000000000000000000000000000000000000000000000000000000000000000","649984435b62b4a25d40c6133e8d9ab8c53d4b059ee8a154a3be0fcf4e892edb", 0),
680            ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff13cea4a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","649984435b62b4a25d40c6133e8d9ab8c53d4b059ee8a154a3be0fcf4e892edb", 0),
681            ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff15028c590063f64d5a7f1c14915cd61eac886ab295bebd91992504cf77edb028bdd6267f","3fde5713f8282eead7d39d4201f44a7c85a5ac8a0681f35e54085c6b69543374", 1),
682            ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff2715de860000000000000000000000000000000000000000000000000000000000000000","3524f77fa3a6eb4389c3cb5d27f1f91462086429cd6c0cb0df43ea8f1e7b3fb4", 0),
683            ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff2715de86fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","3524f77fa3a6eb4389c3cb5d27f1f91462086429cd6c0cb0df43ea8f1e7b3fb4", 0),
684            ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff2c2c5709e7156c417717f2feab147141ec3da19fb759575cc6e37b2ea5ac9309f26f0f66","d2469ab3e04acbb21c65a1809f39caafe7a77c13d10f9dd38f391c01dc499c52", 0),
685            ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff3a08cc1efffffffffffffffffffffffffffffffffffffffffffffffffffffffff760e9f0","38e2a5ce6a93e795e16d2c398bc99f0369202ce21e8f09d56777b40fc512bccc", 1),
686            ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff3e91257d932016cbf69c4471bd1f656c6a107f1973de4af7086db897277060e25677f19a","864b3dc902c376709c10a93ad4bbe29fce0012f3dc8672c6286bba28d7d6d6fc", 0),
687            ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff795d6c1c322cadf599dbb86481522b3cc55f15a67932db2afa0111d9ed6981bcd124bf44","766dfe4a700d9bee288b903ad58870e3d4fe2f0ef780bcac5c823f320d9a9bef", 0),
688            ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff8e426f0392389078c12b1a89e9542f0593bc96b6bfde8224f8654ef5d5cda935a3582194","faec7bc1987b63233fbc5f956edbf37d54404e7461c58ab8631bc68e451a0478", 0),
689            ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff91192139ffffffffffffffffffffffffffffffffffffffffffffffffffffffff45f0f1eb","ec29a50bae138dbf7d8e24825006bb5fc1a2cc1243ba335bc6116fb9e498ec1f", 0),
690            ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff98eb9ab76e84499c483b3bf06214abfe065dddf43b8601de596d63b9e45a166a580541fe","1e0ff2dee9b09b136292a9e910f0d6ac3e552a644bba39e64e9dd3e3bbd3d4d4", 0),
691            ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff9b77b7f2c74d99efceaa550f1ad1c0f43f46e7ff1ee3bd0162b7bf55f2965da9c3450646","8b7dd5c3edba9ee97b70eff438f22dca9849c8254a2f3345a0a572ffeaae0928", 0),
692            ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffff9b77b7f2ffffffffffffffffffffffffffffffffffffffffffffffffffffffff156ca896","0881950c8f51d6b9a6387465d5f12609ef1bb25412a08a74cb2dfb200c74bfbf", 1),
693            ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffa2f5cd838816c16c4fe8a1661d606fdb13cf9af04b979a2e159a09409ebc8645d58fde02","2f083207b9fd9b550063c31cd62b8746bd543bdc5bbf10e3a35563e927f440c8", 0),
694            ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffb13f75c00000000000000000000000000000000000000000000000000000000000000000","4f51e0be078e0cddab2742156adba7e7a148e73157072fd618cd60942b146bd0", 0),
695            ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffb13f75c0fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","4f51e0be078e0cddab2742156adba7e7a148e73157072fd618cd60942b146bd0", 0),
696            ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7bc1f8d0000000000000000000000000000000000000000000000000000000000000000","16c2ccb54352ff4bd794f6efd613c72197ab7082da5b563bdf9cb3edaafe74c2", 0),
697            ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffe7bc1f8dfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","16c2ccb54352ff4bd794f6efd613c72197ab7082da5b563bdf9cb3edaafe74c2", 0),
698            ("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffef64d162750546ce42b0431361e52d4f5242d8f24f33e6b1f99b591647cbc808f462af51","d41244d11ca4f65240687759f95ca9efbab767ededb38fd18c36e18cd3b6f6a9", 1),
699            ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0e5be52372dd6e894b2a326fc3605a6e8f3c69c710bf27d630dfe2004988b78eb6eab36","64bf84dd5e03670fdb24c0f5d3c2c365736f51db6c92d95010716ad2d36134c8", 0),
700            ("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffefbb982fffffffffffffffffffffffffffffffffffffffffffffffffffffffff6d6db1f","1c92ccdfcf4ac550c28db57cff0c8515cb26936c786584a70114008d6c33a34b", 0)
701        );
702
703        for test in tests.iter() {
704            let pk = PublicKey::from_ellswift(ElligatorSwift::from_array(test.enc));
705            assert_eq!(pk, test.key);
706        }
707    }
708}