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