secp256k1_zkp/zkp/
ecdsa_adaptor.rs

1//! # ECDSA Adaptor
2//! Support for ECDSA based adaptor signatures.
3//!
4//! WARNING: ECDSA adaptor signatures are insecure when the secret key is reused
5//! in certain other crypto schemes. See
6//! <https://github.com/ElementsProject/secp256k1-zkp/blob/6955af5ca8930aa674e5fdbc4343e722b25e0ca8/include/secp256k1_ecdsa_adaptor.h#L14>
7//! for details.
8//!
9
10use crate::ffi::{self, CPtr, ECDSA_ADAPTOR_SIGNATURE_LENGTH};
11#[cfg(feature = "rand-std")]
12use crate::rand::thread_rng;
13#[cfg(feature = "actual-rand")]
14use crate::rand::{CryptoRng, Rng};
15use crate::{constants, PublicKey, Secp256k1, SecretKey};
16use crate::{ecdsa::Signature, Verification};
17use crate::{from_hex, Error};
18use crate::{Message, Signing};
19use core::{fmt, ptr, str};
20
21/// Represents an adaptor signature and dleq proof.
22#[derive(Debug, PartialEq, Clone, Copy, Eq)]
23pub struct EcdsaAdaptorSignature(ffi::EcdsaAdaptorSignature);
24
25impl fmt::LowerHex for EcdsaAdaptorSignature {
26    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
27        for ch in self.0.as_ref().iter() {
28            write!(f, "{:02x}", ch)?;
29        }
30        Ok(())
31    }
32}
33
34impl fmt::Display for EcdsaAdaptorSignature {
35    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
36        fmt::LowerHex::fmt(self, f)
37    }
38}
39
40impl str::FromStr for EcdsaAdaptorSignature {
41    type Err = Error;
42    fn from_str(s: &str) -> Result<EcdsaAdaptorSignature, Error> {
43        let mut res = [0; ECDSA_ADAPTOR_SIGNATURE_LENGTH];
44        match from_hex(s, &mut res) {
45            Ok(ECDSA_ADAPTOR_SIGNATURE_LENGTH) => {
46                EcdsaAdaptorSignature::from_slice(&res[0..ECDSA_ADAPTOR_SIGNATURE_LENGTH])
47            }
48            _ => Err(Error::InvalidEcdsaAdaptorSignature),
49        }
50    }
51}
52
53#[cfg(feature = "serde")]
54impl ::serde::Serialize for EcdsaAdaptorSignature {
55    fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
56        if s.is_human_readable() {
57            s.collect_str(self)
58        } else {
59            s.serialize_bytes(self.0.as_ref())
60        }
61    }
62}
63
64#[cfg(feature = "serde")]
65impl<'de> ::serde::Deserialize<'de> for EcdsaAdaptorSignature {
66    fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
67        use crate::serde_util;
68
69        if d.is_human_readable() {
70            d.deserialize_str(serde_util::FromStrVisitor::new("an ASCII hex string"))
71        } else {
72            d.deserialize_bytes(serde_util::BytesVisitor::new(
73                "a bytestring",
74                EcdsaAdaptorSignature::from_slice,
75            ))
76        }
77    }
78}
79
80impl CPtr for EcdsaAdaptorSignature {
81    type Target = ffi::EcdsaAdaptorSignature;
82    fn as_c_ptr(&self) -> *const Self::Target {
83        self.as_ptr()
84    }
85
86    fn as_mut_c_ptr(&mut self) -> *mut Self::Target {
87        self.as_mut_ptr()
88    }
89}
90
91impl AsRef<[u8]> for EcdsaAdaptorSignature {
92    fn as_ref(&self) -> &[u8] {
93        self.0.as_ref()
94    }
95}
96
97impl EcdsaAdaptorSignature {
98    /// Creates an [`EcdsaAdaptorSignature`] directly from a slice
99    #[inline]
100    pub fn from_slice(data: &[u8]) -> Result<EcdsaAdaptorSignature, Error> {
101        match data.len() {
102            ECDSA_ADAPTOR_SIGNATURE_LENGTH => {
103                let mut ret = [0; ECDSA_ADAPTOR_SIGNATURE_LENGTH];
104                ret[..].copy_from_slice(data);
105                unsafe {
106                    Ok(EcdsaAdaptorSignature(
107                        ffi::EcdsaAdaptorSignature::from_array_unchecked(ret),
108                    ))
109                }
110            }
111            _ => Err(Error::InvalidEcdsaAdaptorSignature),
112        }
113    }
114
115    /// Obtains a raw const pointer suitable for use with FFI functions
116    #[inline]
117    pub fn as_ptr(&self) -> *const ffi::EcdsaAdaptorSignature {
118        &self.0
119    }
120
121    /// Obtains a raw mutable pointer suitable for use with FFI functions
122    #[inline]
123    pub fn as_mut_ptr(&mut self) -> *mut ffi::EcdsaAdaptorSignature {
124        &mut self.0
125    }
126}
127
128impl EcdsaAdaptorSignature {
129    /// Creates an adaptor signature along with a proof to verify the adaptor signature.
130    /// This function derives a nonce using a similar process as described in BIP-340.
131    /// The nonce derivation process is strengthened against side channel
132    /// attacks by providing auxiliary randomness using the ThreadRng random number generator.
133    /// Requires compilation with "rand-std" feature.
134    #[cfg(feature = "rand-std")]
135    pub fn encrypt<C: Signing>(
136        secp: &Secp256k1<C>,
137        msg: &Message,
138        sk: &SecretKey,
139        enckey: &PublicKey,
140    ) -> EcdsaAdaptorSignature {
141        let mut rng = thread_rng();
142        EcdsaAdaptorSignature::encrypt_with_rng(secp, msg, sk, enckey, &mut rng)
143    }
144
145    /// Creates an adaptor signature along with a proof to verify the adaptor signature,
146    /// This function derives a nonce using a similar process as described in BIP-340.
147    /// The nonce derivation process is strengthened against side channel
148    /// attacks by providing auxiliary randomness using the provided random number generator.
149    /// Requires compilation with "rand" feature.
150    #[cfg(feature = "actual-rand")]
151    pub fn encrypt_with_rng<C: Signing, R: Rng + CryptoRng>(
152        secp: &Secp256k1<C>,
153        msg: &Message,
154        sk: &SecretKey,
155        enckey: &PublicKey,
156        rng: &mut R,
157    ) -> EcdsaAdaptorSignature {
158        let mut aux = [0u8; 32];
159        rng.fill_bytes(&mut aux);
160        EcdsaAdaptorSignature::encrypt_with_aux_rand(secp, msg, sk, enckey, &aux)
161    }
162
163    /// Creates an adaptor signature along with a proof to verify the adaptor signature,
164    /// without using any auxiliary random data. Note that using this function
165    /// is still considered safe.
166    pub fn encrypt_no_aux_rand<C: Signing>(
167        secp: &Secp256k1<C>,
168        msg: &Message,
169        sk: &SecretKey,
170        enckey: &PublicKey,
171    ) -> EcdsaAdaptorSignature {
172        let mut adaptor_sig = ffi::EcdsaAdaptorSignature::new();
173
174        let res = unsafe {
175            ffi::secp256k1_ecdsa_adaptor_encrypt(
176                secp.ctx().as_ptr(),
177                &mut adaptor_sig,
178                sk.as_c_ptr(),
179                enckey.as_c_ptr(),
180                msg.as_c_ptr(),
181                ffi::secp256k1_nonce_function_ecdsa_adaptor,
182                ptr::null_mut(),
183            )
184        };
185        debug_assert_eq!(res, 1);
186
187        EcdsaAdaptorSignature(adaptor_sig)
188    }
189
190    /// Creates an adaptor signature along with a proof to verify the adaptor signature.
191    /// This function derives a nonce using a similar process as described in BIP-340.
192    /// The nonce derivation process is strengthened against side channel attacks by
193    /// using the provided auxiliary random data.
194    pub fn encrypt_with_aux_rand<C: Signing>(
195        secp: &Secp256k1<C>,
196        msg: &Message,
197        sk: &SecretKey,
198        enckey: &PublicKey,
199        aux_rand: &[u8; 32],
200    ) -> EcdsaAdaptorSignature {
201        let mut adaptor_sig = ffi::EcdsaAdaptorSignature::new();
202
203        let res = unsafe {
204            ffi::secp256k1_ecdsa_adaptor_encrypt(
205                secp.ctx().as_ptr(),
206                &mut adaptor_sig,
207                sk.as_c_ptr(),
208                enckey.as_c_ptr(),
209                msg.as_c_ptr(),
210                ffi::secp256k1_nonce_function_ecdsa_adaptor,
211                aux_rand.as_c_ptr() as *mut ffi::types::c_void,
212            )
213        };
214        debug_assert_eq!(res, 1);
215
216        EcdsaAdaptorSignature(adaptor_sig)
217    }
218
219    /// Creates an ECDSA signature from an adaptor signature and an adaptor secret.
220    pub fn decrypt(&self, decryption_key: &SecretKey) -> Result<Signature, Error> {
221        unsafe {
222            let mut signature = ffi::Signature::new();
223            let ret = ffi::secp256k1_ecdsa_adaptor_decrypt(
224                ffi::secp256k1_context_no_precomp,
225                &mut signature,
226                decryption_key.as_c_ptr(),
227                self.as_c_ptr(),
228            );
229
230            if ret != 1 {
231                return Err(Error::CannotDecryptAdaptorSignature);
232            }
233
234            Ok(Signature::from(signature))
235        }
236    }
237
238    /// Extracts the adaptor secret from the complete signature and the adaptor signature.
239    pub fn recover<C: Signing>(
240        &self,
241        secp: &Secp256k1<C>,
242        sig: &Signature,
243        encryption_key: &PublicKey,
244    ) -> Result<SecretKey, Error> {
245        let mut data: [u8; constants::SECRET_KEY_SIZE] = [0; constants::SECRET_KEY_SIZE];
246
247        let ret = unsafe {
248            ffi::secp256k1_ecdsa_adaptor_recover(
249                secp.ctx().as_ptr(),
250                data.as_mut_c_ptr(),
251                sig.as_c_ptr(),
252                self.as_c_ptr(),
253                encryption_key.as_c_ptr(),
254            )
255        };
256
257        if ret != 1 {
258            return Err(Error::CannotRecoverAdaptorSecret);
259        }
260
261        Ok(SecretKey::from_slice(&data)?)
262    }
263
264    /// Verifies that the adaptor secret can be extracted from the adaptor signature and the completed ECDSA signature.
265    pub fn verify<C: Verification>(
266        &self,
267        secp: &Secp256k1<C>,
268        msg: &Message,
269        pubkey: &PublicKey,
270        encryption_key: &PublicKey,
271    ) -> Result<(), Error> {
272        let res = unsafe {
273            ffi::secp256k1_ecdsa_adaptor_verify(
274                secp.ctx().as_ptr(),
275                self.as_c_ptr(),
276                pubkey.as_c_ptr(),
277                msg.as_c_ptr(),
278                encryption_key.as_c_ptr(),
279            )
280        };
281
282        if res != 1 {
283            return Err(Error::CannotVerifyAdaptorSignature);
284        };
285
286        Ok(())
287    }
288}
289
290#[cfg(all(test, feature = "global-context"))]
291mod tests {
292    use super::Message;
293    use super::*;
294    #[cfg(not(rust_secp_fuzz))]
295    use crate::rand::{rngs::ThreadRng, thread_rng, RngCore};
296    use crate::SECP256K1;
297
298    #[cfg(not(rust_secp_fuzz))]
299    fn test_ecdsa_adaptor_signature_helper(
300        encrypt: fn(&Message, &SecretKey, &PublicKey, &mut ThreadRng) -> EcdsaAdaptorSignature,
301    ) {
302        let mut rng = thread_rng();
303        let (seckey, pubkey) = SECP256K1.generate_keypair(&mut rng);
304        let (adaptor_secret, adaptor) = SECP256K1.generate_keypair(&mut rng);
305        let msg = Message::from_digest_slice(&[2u8; 32]).unwrap();
306        let adaptor_sig = encrypt(&msg, &seckey, &adaptor, &mut rng);
307
308        adaptor_sig
309            .verify(SECP256K1, &msg, &pubkey, &adaptor)
310            .expect("adaptor signature to be valid");
311        adaptor_sig
312            .verify(SECP256K1, &msg, &adaptor, &pubkey)
313            .expect_err("adaptor signature to be invalid");
314        let sig = adaptor_sig
315            .decrypt(&adaptor_secret)
316            .expect("to be able to decrypt using the correct secret");
317        SECP256K1
318            .verify_ecdsa(&msg, &sig, &pubkey)
319            .expect("signature to be valid");
320        let recovered = adaptor_sig
321            .recover(SECP256K1, &sig, &adaptor)
322            .expect("to be able to recover the secret");
323        assert_eq!(adaptor_secret, recovered);
324    }
325
326    #[test]
327    #[cfg(not(rust_secp_fuzz))]
328    fn test_ecdsa_adaptor_signature_encrypt() {
329        test_ecdsa_adaptor_signature_helper(|msg, sk, adaptor, _| {
330            EcdsaAdaptorSignature::encrypt(SECP256K1, msg, sk, adaptor)
331        })
332    }
333
334    #[test]
335    #[cfg(not(rust_secp_fuzz))]
336    fn test_ecdsa_adaptor_signature_encrypt_with_rng() {
337        test_ecdsa_adaptor_signature_helper(|msg, sk, adaptor, rng| {
338            EcdsaAdaptorSignature::encrypt_with_rng(SECP256K1, msg, sk, adaptor, rng)
339        })
340    }
341
342    #[test]
343    #[cfg(not(rust_secp_fuzz))]
344    fn test_ecdsa_adaptor_signature_encrypt_with_aux_rand() {
345        test_ecdsa_adaptor_signature_helper(|msg, sk, adaptor, rng| {
346            let mut aux_rand = [0; 32];
347            rng.fill_bytes(&mut aux_rand);
348            EcdsaAdaptorSignature::encrypt_with_aux_rand(SECP256K1, msg, sk, adaptor, &aux_rand)
349        })
350    }
351
352    #[test]
353    #[cfg(not(rust_secp_fuzz))]
354    fn test_ecdsa_adaptor_signature_encrypt_no_aux_rand() {
355        test_ecdsa_adaptor_signature_helper(|msg, sk, adaptor, _| {
356            EcdsaAdaptorSignature::encrypt_no_aux_rand(SECP256K1, msg, sk, adaptor)
357        })
358    }
359
360    #[test]
361    fn test_ecdsa_adaptor_signature_plain_valid() {
362        let msg = msg_from_str("8131e6f4b45754f2c90bd06688ceeabc0c45055460729928b4eecf11026a9e2d");
363        let pubkey = "035be5e9478209674a96e60f1f037f6176540fd001fa1d64694770c56a7709c42c"
364            .parse()
365            .unwrap();
366        let encryption_key = "02c2662c97488b07b6e819124b8989849206334a4c2fbdf691f7b34d2b16e9c293"
367            .parse()
368            .unwrap();
369        let adaptor_sig : EcdsaAdaptorSignature = "03424d14a5471c048ab87b3b83f6085d125d5864249ae4297a57c84e74710bb6730223f325042fce535d040fee52ec13231bf709ccd84233c6944b90317e62528b2527dff9d659a96db4c99f9750168308633c1867b70f3a18fb0f4539a1aecedcd1fc0148fc22f36b6303083ece3f872b18e35d368b3958efe5fb081f7716736ccb598d269aa3084d57e1855e1ea9a45efc10463bbf32ae378029f5763ceb40173f"
370            .parse()
371            .unwrap();
372
373        adaptor_sig
374            .verify(SECP256K1, &msg, &pubkey, &encryption_key)
375            .expect("adaptor signature verification to pass");
376
377        let sig = compact_sig_from_str("424d14a5471c048ab87b3b83f6085d125d5864249ae4297a57c84e74710bb67329e80e0ee60e57af3e625bbae1672b1ecaa58effe613426b024fa1621d903394");
378        let expected_decryption_key: SecretKey =
379            "0b2aba63b885a0f0e96fa0f303920c7fb7431ddfa94376ad94d969fbf4109dc8"
380                .parse()
381                .unwrap();
382
383        let recovered = adaptor_sig
384            .recover(SECP256K1, &sig, &encryption_key)
385            .expect("to be able to recover the decryption key");
386
387        assert_eq!(expected_decryption_key, recovered);
388    }
389
390    #[test]
391    fn test_ecdsa_adaptor_signature_wrong_proof() {
392        let msg = msg_from_str("8131e6f4b45754f2c90bd06688ceeabc0c45055460729928b4eecf11026a9e2d");
393        let pubkey = "035be5e9478209674a96e60f1f037f6176540fd001fa1d64694770c56a7709c42c"
394            .parse()
395            .unwrap();
396        let encryption_key = "0214ccb756249ad6e733c80285ea7ac2ee12ffebbcee4e556e6810793a60c45ad4"
397            .parse()
398            .unwrap();
399        let adaptor_sig: EcdsaAdaptorSignature = "03f94dca206d7582c015fb9bffe4e43b14591b30ef7d2b464d103ec5e116595dba03127f8ac3533d249280332474339000922eb6a58e3b9bf4fc7e01e4b4df2b7a4100a1e089f16e5d70bb89f961516f1de0684cc79db978495df2f399b0d01ed7240fa6e3252aedb58bdc6b5877b0c602628a235dd1ccaebdddcbe96198c0c21bead7b05f423b673d14d206fa1507b2dbe2722af792b8c266fc25a2d901d7e2c335"
400            .parse()
401            .unwrap();
402
403        adaptor_sig
404            .verify(SECP256K1, &msg, &pubkey, &encryption_key)
405            .expect_err("providing a wrong proof should fail validation");
406    }
407
408    #[test]
409    fn test_ecdsa_adaptor_signature_recover_wrong_sig_r_value() {
410        let encryption_key = "035176d24129741b0fcaa5fd6750727ce30860447e0a92c9ebebdeb7c3f93995ed"
411            .parse()
412            .unwrap();
413        let adaptor_sig: EcdsaAdaptorSignature = "03aa86d78059a91059c29ec1a757c4dc029ff636a1e6c1142fefe1e9d7339617c003a8153e50c0c8574a38d389e61bbb0b5815169e060924e4b5f2e78ff13aa7ad858e0c27c4b9eed9d60521b3f54ff83ca4774be5fb3a680f820a35e8840f4aaf2de88e7c5cff38a37b78725904ef97bb82341328d55987019bd38ae1745e3efe0f8ea8bdfede0d378fc1f96e944a7505249f41e93781509ee0bade77290d39cd12"
414            .parse()
415            .unwrap();
416
417        let sig = compact_sig_from_str("f7f7fe6bd056fc4abd70d335f72d0aa1e8406bba68f3e579e4789475323564a452c46176c7fb40aa37d5651341f55697dab27d84a213b30c93011a7790bace8c");
418        adaptor_sig
419            .recover(SECP256K1, &sig, &encryption_key)
420            .expect_err("providing wrong r value should prevent us from recovering decryption key");
421    }
422
423    #[test]
424    fn test_ecdsa_adaptor_signature_recover_from_high_s_signature() {
425        let encryption_key = "02042537e913ad74c4bbd8da9607ad3b9cb297d08e014afc51133083f1bd687a62"
426            .parse()
427            .unwrap();
428        let adaptor_sig: EcdsaAdaptorSignature = "032c637cd797dd8c2ce261907ed43e82d6d1a48cbabbbece801133dd8d70a01b1403eb615a3e59b1cbbf4f87acaf645be1eda32a066611f35dd5557802802b14b19c81c04c3fefac5783b2077bd43fa0a39ab8a64d4d78332a5d621ea23eca46bc011011ab82dda6deb85699f508744d70d4134bea03f784d285b5c6c15a56e4e1fab4bc356abbdebb3b8fe1e55e6dd6d2a9ea457e91b2e6642fae69f9dbb5258854"
429            .parse()
430            .unwrap();
431
432        let sig = compact_sig_from_str("2c637cd797dd8c2ce261907ed43e82d6d1a48cbabbbece801133dd8d70a01b14b5f24321f550b7b9dd06ee4fcfd82bdad8b142ff93a790cc4d9f7962b38c6a3b");
433        let expected_decryption_key: SecretKey =
434            "324719b51ff2474c9438eb76494b0dc0bcceeb529f0a5428fd198ad8f886e99c"
435                .parse()
436                .unwrap();
437        let recovered = adaptor_sig
438            .recover(SECP256K1, &sig, &encryption_key)
439            .expect("with high s we should still be able to recover the decryption key");
440
441        assert_eq!(expected_decryption_key, recovered);
442    }
443
444    #[cfg(feature = "serde")]
445    #[test]
446    fn test_ecdsa_adaptor_sig_de_serialization() {
447        use serde_test::Configure;
448        use serde_test::{assert_tokens, Token};
449
450        let sig = EcdsaAdaptorSignature::from_slice(&[
451            3, 44, 99, 124, 215, 151, 221, 140, 44, 226, 97, 144, 126, 212, 62, 130, 214, 209, 164,
452            140, 186, 187, 190, 206, 128, 17, 51, 221, 141, 112, 160, 27, 20, 3, 235, 97, 90, 62,
453            89, 177, 203, 191, 79, 135, 172, 175, 100, 91, 225, 237, 163, 42, 6, 102, 17, 243, 93,
454            213, 85, 120, 2, 128, 43, 20, 177, 156, 129, 192, 76, 63, 239, 172, 87, 131, 178, 7,
455            123, 212, 63, 160, 163, 154, 184, 166, 77, 77, 120, 51, 42, 93, 98, 30, 162, 62, 202,
456            70, 188, 1, 16, 17, 171, 130, 221, 166, 222, 184, 86, 153, 245, 8, 116, 77, 112, 212,
457            19, 75, 234, 3, 247, 132, 210, 133, 181, 198, 193, 90, 86, 228, 225, 250, 180, 188, 53,
458            106, 187, 222, 187, 59, 143, 225, 229, 94, 109, 214, 210, 169, 234, 69, 126, 145, 178,
459            230, 100, 47, 174, 105, 249, 219, 181, 37, 136, 84,
460        ])
461        .unwrap();
462
463        assert_tokens(
464            &sig.readable(),
465            &[Token::Str(
466                "032c637cd797dd8c2ce261907ed43e82d6d1a48cbabbbece801133dd8d70a01b1403eb615a3e59b1cbbf4f87acaf645be1eda32a066611f35dd5557802802b14b19c81c04c3fefac5783b2077bd43fa0a39ab8a64d4d78332a5d621ea23eca46bc011011ab82dda6deb85699f508744d70d4134bea03f784d285b5c6c15a56e4e1fab4bc356abbdebb3b8fe1e55e6dd6d2a9ea457e91b2e6642fae69f9dbb5258854",
467            )],
468        );
469
470        assert_tokens(
471            &sig.compact(),
472            &[Token::Bytes(&[
473                3, 44, 99, 124, 215, 151, 221, 140, 44, 226, 97, 144, 126, 212, 62, 130, 214, 209,
474                164, 140, 186, 187, 190, 206, 128, 17, 51, 221, 141, 112, 160, 27, 20, 3, 235, 97,
475                90, 62, 89, 177, 203, 191, 79, 135, 172, 175, 100, 91, 225, 237, 163, 42, 6, 102,
476                17, 243, 93, 213, 85, 120, 2, 128, 43, 20, 177, 156, 129, 192, 76, 63, 239, 172,
477                87, 131, 178, 7, 123, 212, 63, 160, 163, 154, 184, 166, 77, 77, 120, 51, 42, 93,
478                98, 30, 162, 62, 202, 70, 188, 1, 16, 17, 171, 130, 221, 166, 222, 184, 86, 153,
479                245, 8, 116, 77, 112, 212, 19, 75, 234, 3, 247, 132, 210, 133, 181, 198, 193, 90,
480                86, 228, 225, 250, 180, 188, 53, 106, 187, 222, 187, 59, 143, 225, 229, 94, 109,
481                214, 210, 169, 234, 69, 126, 145, 178, 230, 100, 47, 174, 105, 249, 219, 181, 37,
482                136, 84,
483            ])],
484        );
485    }
486
487    fn msg_from_str(input: &str) -> Message {
488        let mut buf = [0u8; 32];
489        from_hex(input, &mut buf).unwrap();
490        Message::from_digest_slice(&buf).unwrap()
491    }
492
493    fn compact_sig_from_str(input: &str) -> Signature {
494        let mut buf = [0u8; 64];
495        from_hex(input, &mut buf).unwrap();
496        Signature::from_compact(&buf).unwrap()
497    }
498}