chie_crypto/
adaptor.rs

1//! Adaptor Signatures for Atomic Swaps.
2//!
3//! Adaptor signatures enable atomic swaps and scriptless scripts by "locking"
4//! a signature to a secret value. Once the signature is published, the secret
5//! is automatically revealed, enabling trustless cross-chain atomic swaps.
6//!
7//! # Protocol Overview
8//!
9//! 1. Alice generates a secret `t` and publishes the adaptor point `T = t*G`
10//! 2. Bob creates a pre-signature that's "locked" to `T`
11//! 3. Alice can verify the pre-signature is correct
12//! 4. Alice completes the signature using her secret `t`
13//! 5. When Alice publishes the complete signature, Bob can extract `t`
14//! 6. Bob can now use `t` to claim funds on another chain
15//!
16//! # Example
17//!
18//! ```
19//! use chie_crypto::adaptor::*;
20//!
21//! // Alice generates a secret for the atomic swap
22//! let secret = AdaptorSecret::random();
23//! let adaptor_point = secret.to_point();
24//!
25//! // Bob creates a locked signature
26//! let signer = AdaptorSigner::new();
27//! let message = b"Payment to Alice";
28//!
29//! let pre_sig = signer.create_pre_signature_with_secret(message, &secret).unwrap();
30//!
31//! // Alice verifies the pre-signature is valid
32//! assert!(verify_pre_signature(&signer.public_key(), message, &pre_sig, &adaptor_point));
33//!
34//! // Alice completes the signature using her secret
35//! let complete_sig = complete_signature(&pre_sig, &secret).unwrap();
36//!
37//! // Alice publishes the complete signature
38//! assert!(verify_adaptor_signature(&signer.public_key(), message, &complete_sig));
39//!
40//! // Bob extracts Alice's secret from the signatures
41//! let extracted = extract_secret(&pre_sig, &complete_sig, &adaptor_point).unwrap();
42//! assert_eq!(secret.to_bytes(), extracted.to_bytes());
43//! ```
44
45use blake3::Hasher;
46use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT;
47use curve25519_dalek::ristretto::RistrettoPoint;
48use curve25519_dalek::scalar::Scalar;
49use rand::RngCore;
50use serde::{Deserialize, Serialize};
51use thiserror::Error;
52
53#[derive(Debug, Error)]
54pub enum AdaptorError {
55    #[error("Invalid public key")]
56    InvalidPublicKey,
57    #[error("Invalid signature")]
58    InvalidSignature,
59    #[error("Invalid adaptor point")]
60    InvalidAdaptorPoint,
61    #[error("Secret extraction failed")]
62    SecretExtractionFailed,
63    #[error("Serialization error: {0}")]
64    Serialization(String),
65}
66
67pub type AdaptorResult<T> = Result<T, AdaptorError>;
68
69/// Generate a random scalar
70fn random_scalar() -> Scalar {
71    let mut bytes = [0u8; 32];
72    rand::thread_rng().fill_bytes(&mut bytes);
73    Scalar::from_bytes_mod_order(bytes)
74}
75
76/// Secret key for adaptor signatures
77#[derive(Clone, Serialize, Deserialize)]
78pub struct AdaptorSecretKey(Scalar);
79
80/// Public key for adaptor signatures
81#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
82pub struct AdaptorPublicKey(RistrettoPoint);
83
84/// The secret value used to lock/unlock signatures
85#[derive(Clone, Serialize, Deserialize)]
86pub struct AdaptorSecret(Scalar);
87
88/// The public adaptor point (commitment to the secret)
89#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
90pub struct AdaptorPoint(RistrettoPoint);
91
92/// Signer for adaptor signatures
93#[derive(Clone)]
94pub struct AdaptorSigner {
95    secret_key: AdaptorSecretKey,
96    public_key: AdaptorPublicKey,
97}
98
99/// Pre-signature (locked to an adaptor point)
100#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
101pub struct PreSignature {
102    r_prime: RistrettoPoint, // R' = R + T
103    s_prime: Scalar,         // s' (partial signature)
104}
105
106/// Complete signature (standard Schnorr signature)
107#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
108pub struct AdaptorSignature {
109    r: RistrettoPoint,
110    s: Scalar,
111}
112
113impl AdaptorSecret {
114    /// Generate a random secret
115    pub fn random() -> Self {
116        Self(random_scalar())
117    }
118
119    /// Create secret from bytes
120    pub fn from_bytes(bytes: &[u8; 32]) -> Self {
121        Self(Scalar::from_bytes_mod_order(*bytes))
122    }
123
124    /// Export secret to bytes
125    pub fn to_bytes(&self) -> [u8; 32] {
126        self.0.to_bytes()
127    }
128
129    /// Get the adaptor point (public commitment)
130    pub fn to_point(&self) -> AdaptorPoint {
131        AdaptorPoint(RISTRETTO_BASEPOINT_POINT * self.0)
132    }
133}
134
135impl AdaptorPoint {
136    /// Create from bytes
137    pub fn from_bytes(bytes: &[u8; 32]) -> AdaptorResult<Self> {
138        let point = curve25519_dalek::ristretto::CompressedRistretto(*bytes)
139            .decompress()
140            .ok_or(AdaptorError::InvalidAdaptorPoint)?;
141        Ok(Self(point))
142    }
143
144    /// Export to bytes
145    pub fn to_bytes(&self) -> [u8; 32] {
146        self.0.compress().to_bytes()
147    }
148}
149
150impl AdaptorSigner {
151    /// Create a new random signer
152    pub fn new() -> Self {
153        let secret = random_scalar();
154        let public = RISTRETTO_BASEPOINT_POINT * secret;
155
156        Self {
157            secret_key: AdaptorSecretKey(secret),
158            public_key: AdaptorPublicKey(public),
159        }
160    }
161
162    /// Create from secret key bytes
163    pub fn from_bytes(bytes: &[u8; 32]) -> AdaptorResult<Self> {
164        let secret = Scalar::from_bytes_mod_order(*bytes);
165        let public = RISTRETTO_BASEPOINT_POINT * secret;
166
167        Ok(Self {
168            secret_key: AdaptorSecretKey(secret),
169            public_key: AdaptorPublicKey(public),
170        })
171    }
172
173    /// Get the public key
174    pub fn public_key(&self) -> AdaptorPublicKey {
175        self.public_key
176    }
177
178    /// Export secret key to bytes
179    pub fn to_bytes(&self) -> [u8; 32] {
180        self.secret_key.0.to_bytes()
181    }
182
183    /// Create a pre-signature (locked to adaptor point)
184    ///
185    /// This creates a signature that can only be completed by someone who knows
186    /// the adaptor secret `t` corresponding to the adaptor point `T = t*G`.
187    ///
188    /// The pre-signature is (R', s') where R' = R + T and s' = k + c*x (standard Schnorr).
189    /// To complete, the holder of t computes s = s' + t.
190    pub fn create_pre_signature_with_secret(
191        &self,
192        message: &[u8],
193        adaptor_secret: &AdaptorSecret,
194    ) -> AdaptorResult<PreSignature> {
195        let adaptor = adaptor_secret.to_point();
196
197        // Generate nonce
198        let k = random_scalar();
199        let r = RISTRETTO_BASEPOINT_POINT * k;
200
201        // R' = R + T (this is what gets transmitted)
202        let r_prime = r + adaptor.0;
203
204        // Compute challenge: c = H(R', X, m) - use R'!
205        let challenge = compute_challenge(&r_prime, &self.public_key, message);
206
207        // s' = k + c*x (standard Schnorr, NO adaptor secret!)
208        let s_prime = k + challenge * self.secret_key.0;
209
210        Ok(PreSignature { r_prime, s_prime })
211    }
212
213    /// Create a pre-signature (for compatibility - same as create_pre_signature_with_secret)
214    ///
215    /// Note: This version requires the adaptor point but internally needs the secret.
216    /// This is a simplified API. For proper adaptor signatures where the signer
217    /// doesn't know the adaptor secret, see ECDSA adaptor signatures.
218    pub fn create_pre_signature(
219        &self,
220        message: &[u8],
221        adaptor: &AdaptorPoint,
222    ) -> AdaptorResult<PreSignature> {
223        // For this simplified version, we generate a temporary secret
224        // In practice, the adaptor secret should be provided by the protocol
225
226        // Generate nonce
227        let k = random_scalar();
228        let r = RISTRETTO_BASEPOINT_POINT * k;
229
230        // R' = R + T
231        let r_prime = r + adaptor.0;
232
233        // Compute challenge: c = H(R', X, m)
234        let challenge = compute_challenge(&r_prime, &self.public_key, message);
235
236        // For now, create a standard signature that can be verified
237        // s' = k + c*x (we can't include t since we don't have it)
238        let s_prime = k + challenge * self.secret_key.0;
239
240        Ok(PreSignature { r_prime, s_prime })
241    }
242}
243
244impl Default for AdaptorSigner {
245    fn default() -> Self {
246        Self::new()
247    }
248}
249
250impl AdaptorPublicKey {
251    /// Create from bytes
252    pub fn from_bytes(bytes: &[u8; 32]) -> AdaptorResult<Self> {
253        let point = curve25519_dalek::ristretto::CompressedRistretto(*bytes)
254            .decompress()
255            .ok_or(AdaptorError::InvalidPublicKey)?;
256        Ok(Self(point))
257    }
258
259    /// Export to bytes
260    pub fn to_bytes(&self) -> [u8; 32] {
261        self.0.compress().to_bytes()
262    }
263}
264
265/// Compute challenge for Schnorr signature
266fn compute_challenge(r: &RistrettoPoint, pubkey: &AdaptorPublicKey, message: &[u8]) -> Scalar {
267    let mut hasher = Hasher::new();
268    hasher.update(&r.compress().to_bytes());
269    hasher.update(&pubkey.0.compress().to_bytes());
270    hasher.update(message);
271
272    let hash = hasher.finalize();
273    Scalar::from_bytes_mod_order(*hash.as_bytes())
274}
275
276/// Verify a pre-signature is valid
277///
278/// Checks that s'*G = R + c*X where R = R' - T and c = H(R', X, m)
279pub fn verify_pre_signature(
280    pubkey: &AdaptorPublicKey,
281    message: &[u8],
282    pre_sig: &PreSignature,
283    adaptor: &AdaptorPoint,
284) -> bool {
285    // Recover R = R' - T
286    let r = pre_sig.r_prime - adaptor.0;
287
288    // Compute challenge: c = H(R', X, m) - using R'!
289    let challenge = compute_challenge(&pre_sig.r_prime, pubkey, message);
290
291    // Verify: s'*G = R + c*X
292    let lhs = RISTRETTO_BASEPOINT_POINT * pre_sig.s_prime;
293    let rhs = r + challenge * pubkey.0;
294
295    lhs == rhs
296}
297
298/// Complete a pre-signature using the adaptor secret
299///
300/// Given a pre-signature (R', s') where s' = k + c*x,
301/// this produces a complete signature (R', s) where s = s' + t.
302pub fn complete_signature(
303    pre_sig: &PreSignature,
304    secret: &AdaptorSecret,
305) -> AdaptorResult<AdaptorSignature> {
306    // R stays as R'
307    let r = pre_sig.r_prime;
308
309    // s = s' + t (ADD the adaptor secret!)
310    let s = pre_sig.s_prime + secret.0;
311
312    Ok(AdaptorSignature { r, s })
313}
314
315/// Verify a complete adaptor signature
316pub fn verify_adaptor_signature(
317    pubkey: &AdaptorPublicKey,
318    message: &[u8],
319    signature: &AdaptorSignature,
320) -> bool {
321    // Compute challenge: c = H(R, X, m)
322    let challenge = compute_challenge(&signature.r, pubkey, message);
323
324    // Verify standard Schnorr signature: s*G = R + c*X
325    let lhs = RISTRETTO_BASEPOINT_POINT * signature.s;
326    let rhs = signature.r + challenge * pubkey.0;
327
328    lhs == rhs
329}
330
331/// Extract the secret from pre-signature and complete signature
332///
333/// Given s' and s where s = s' + t, this computes t = s - s'.
334pub fn extract_secret(
335    pre_sig: &PreSignature,
336    complete_sig: &AdaptorSignature,
337    adaptor: &AdaptorPoint,
338) -> AdaptorResult<AdaptorSecret> {
339    // t = s - s' (since s = s' + t)
340    let t = complete_sig.s - pre_sig.s_prime;
341
342    // Verify: T = t*G
343    let computed_adaptor = RISTRETTO_BASEPOINT_POINT * t;
344    if computed_adaptor != adaptor.0 {
345        return Err(AdaptorError::SecretExtractionFailed);
346    }
347
348    Ok(AdaptorSecret(t))
349}
350
351impl PreSignature {
352    /// Serialize to bytes
353    pub fn to_bytes(&self) -> [u8; 64] {
354        let mut bytes = [0u8; 64];
355        bytes[..32].copy_from_slice(&self.r_prime.compress().to_bytes());
356        bytes[32..].copy_from_slice(&self.s_prime.to_bytes());
357        bytes
358    }
359
360    /// Deserialize from bytes
361    pub fn from_bytes(bytes: &[u8; 64]) -> AdaptorResult<Self> {
362        let r_prime =
363            curve25519_dalek::ristretto::CompressedRistretto(bytes[..32].try_into().unwrap())
364                .decompress()
365                .ok_or(AdaptorError::InvalidSignature)?;
366        let s_prime = Scalar::from_bytes_mod_order(bytes[32..].try_into().unwrap());
367
368        Ok(Self { r_prime, s_prime })
369    }
370}
371
372impl AdaptorSignature {
373    /// Serialize to bytes
374    pub fn to_bytes(&self) -> [u8; 64] {
375        let mut bytes = [0u8; 64];
376        bytes[..32].copy_from_slice(&self.r.compress().to_bytes());
377        bytes[32..].copy_from_slice(&self.s.to_bytes());
378        bytes
379    }
380
381    /// Deserialize from bytes
382    pub fn from_bytes(bytes: &[u8; 64]) -> AdaptorResult<Self> {
383        let r = curve25519_dalek::ristretto::CompressedRistretto(bytes[..32].try_into().unwrap())
384            .decompress()
385            .ok_or(AdaptorError::InvalidSignature)?;
386        let s = Scalar::from_bytes_mod_order(bytes[32..].try_into().unwrap());
387
388        Ok(Self { r, s })
389    }
390}
391
392#[cfg(test)]
393mod tests {
394    use super::*;
395
396    #[test]
397    fn test_adaptor_basic() {
398        let secret = AdaptorSecret::random();
399        let adaptor = secret.to_point();
400
401        let signer = AdaptorSigner::new();
402        let message = b"Test message";
403
404        let pre_sig = signer
405            .create_pre_signature_with_secret(message, &secret)
406            .unwrap();
407        assert!(verify_pre_signature(
408            &signer.public_key(),
409            message,
410            &pre_sig,
411            &adaptor
412        ));
413
414        let complete_sig = complete_signature(&pre_sig, &secret).unwrap();
415        assert!(verify_adaptor_signature(
416            &signer.public_key(),
417            message,
418            &complete_sig
419        ));
420
421        let extracted = extract_secret(&pre_sig, &complete_sig, &adaptor).unwrap();
422        assert_eq!(secret.to_bytes(), extracted.to_bytes());
423    }
424
425    #[test]
426    fn test_adaptor_wrong_secret() {
427        let secret = AdaptorSecret::random();
428        let _adaptor = secret.to_point();
429
430        let signer = AdaptorSigner::new();
431        let message = b"Test message";
432
433        let pre_sig = signer
434            .create_pre_signature_with_secret(message, &secret)
435            .unwrap();
436
437        // Use wrong secret to complete
438        let wrong_secret = AdaptorSecret::random();
439        let complete_sig = complete_signature(&pre_sig, &wrong_secret).unwrap();
440
441        // Signature won't verify
442        assert!(!verify_adaptor_signature(
443            &signer.public_key(),
444            message,
445            &complete_sig
446        ));
447    }
448
449    #[test]
450    fn test_adaptor_wrong_message() {
451        let secret = AdaptorSecret::random();
452        let _adaptor = secret.to_point();
453
454        let signer = AdaptorSigner::new();
455        let message = b"Original message";
456
457        let pre_sig = signer
458            .create_pre_signature_with_secret(message, &secret)
459            .unwrap();
460        let complete_sig = complete_signature(&pre_sig, &secret).unwrap();
461
462        // Verify with wrong message
463        assert!(!verify_adaptor_signature(
464            &signer.public_key(),
465            b"Wrong message",
466            &complete_sig
467        ));
468    }
469
470    #[test]
471    fn test_secret_extraction_fails_wrong_adaptor() {
472        let secret = AdaptorSecret::random();
473        let _adaptor = secret.to_point();
474
475        let signer = AdaptorSigner::new();
476        let message = b"Test message";
477
478        let pre_sig = signer
479            .create_pre_signature_with_secret(message, &secret)
480            .unwrap();
481        let complete_sig = complete_signature(&pre_sig, &secret).unwrap();
482
483        // Try to extract with wrong adaptor
484        let wrong_adaptor = AdaptorSecret::random().to_point();
485        let result = extract_secret(&pre_sig, &complete_sig, &wrong_adaptor);
486        assert!(result.is_err());
487    }
488
489    #[test]
490    fn test_pre_signature_serialization() {
491        let secret = AdaptorSecret::random();
492        let adaptor = secret.to_point();
493
494        let signer = AdaptorSigner::new();
495        let message = b"Test message";
496
497        let pre_sig = signer
498            .create_pre_signature_with_secret(message, &secret)
499            .unwrap();
500        let bytes = pre_sig.to_bytes();
501        let recovered = PreSignature::from_bytes(&bytes).unwrap();
502
503        assert!(verify_pre_signature(
504            &signer.public_key(),
505            message,
506            &recovered,
507            &adaptor
508        ));
509    }
510
511    #[test]
512    fn test_complete_signature_serialization() {
513        let secret = AdaptorSecret::random();
514        let _adaptor = secret.to_point();
515
516        let signer = AdaptorSigner::new();
517        let message = b"Test message";
518
519        let pre_sig = signer
520            .create_pre_signature_with_secret(message, &secret)
521            .unwrap();
522        let complete_sig = complete_signature(&pre_sig, &secret).unwrap();
523
524        let bytes = complete_sig.to_bytes();
525        let recovered = AdaptorSignature::from_bytes(&bytes).unwrap();
526
527        assert!(verify_adaptor_signature(
528            &signer.public_key(),
529            message,
530            &recovered
531        ));
532    }
533
534    #[test]
535    fn test_signer_serialization() {
536        let signer = AdaptorSigner::new();
537        let bytes = signer.to_bytes();
538        let recovered = AdaptorSigner::from_bytes(&bytes).unwrap();
539
540        assert_eq!(
541            signer.public_key().to_bytes(),
542            recovered.public_key().to_bytes()
543        );
544    }
545
546    #[test]
547    fn test_secret_serialization() {
548        let secret = AdaptorSecret::random();
549        let bytes = secret.to_bytes();
550        let recovered = AdaptorSecret::from_bytes(&bytes);
551
552        assert_eq!(secret.to_bytes(), recovered.to_bytes());
553        assert_eq!(
554            secret.to_point().to_bytes(),
555            recovered.to_point().to_bytes()
556        );
557    }
558
559    #[test]
560    fn test_adaptor_point_serialization() {
561        let secret = AdaptorSecret::random();
562        let adaptor = secret.to_point();
563
564        let bytes = adaptor.to_bytes();
565        let recovered = AdaptorPoint::from_bytes(&bytes).unwrap();
566
567        assert_eq!(adaptor.to_bytes(), recovered.to_bytes());
568    }
569
570    #[test]
571    fn test_multiple_pre_signatures_same_message() {
572        let secret = AdaptorSecret::random();
573        let adaptor = secret.to_point();
574
575        let signer = AdaptorSigner::new();
576        let message = b"Same message";
577
578        let pre_sig1 = signer
579            .create_pre_signature_with_secret(message, &secret)
580            .unwrap();
581        let pre_sig2 = signer
582            .create_pre_signature_with_secret(message, &secret)
583            .unwrap();
584
585        // Both pre-signatures should be valid
586        assert!(verify_pre_signature(
587            &signer.public_key(),
588            message,
589            &pre_sig1,
590            &adaptor
591        ));
592        assert!(verify_pre_signature(
593            &signer.public_key(),
594            message,
595            &pre_sig2,
596            &adaptor
597        ));
598
599        // But they should be different (different nonces)
600        assert_ne!(pre_sig1.to_bytes(), pre_sig2.to_bytes());
601    }
602
603    #[test]
604    fn test_atomic_swap_scenario() {
605        // Alice and Bob want to do an atomic swap
606        // Alice generates a secret
607        let alice_secret = AdaptorSecret::random();
608        let adaptor = alice_secret.to_point();
609
610        // Bob creates a locked payment to Alice
611        let bob = AdaptorSigner::new();
612        let payment_to_alice = b"Payment from Bob to Alice for 1 BTC";
613
614        let pre_sig = bob
615            .create_pre_signature_with_secret(payment_to_alice, &alice_secret)
616            .unwrap();
617
618        // Alice verifies Bob's pre-signature
619        assert!(verify_pre_signature(
620            &bob.public_key(),
621            payment_to_alice,
622            &pre_sig,
623            &adaptor
624        ));
625
626        // Alice completes the signature to claim the payment
627        let complete_sig = complete_signature(&pre_sig, &alice_secret).unwrap();
628        assert!(verify_adaptor_signature(
629            &bob.public_key(),
630            payment_to_alice,
631            &complete_sig
632        ));
633
634        // Bob extracts Alice's secret from the published signature
635        let extracted_secret = extract_secret(&pre_sig, &complete_sig, &adaptor).unwrap();
636        assert_eq!(alice_secret.to_bytes(), extracted_secret.to_bytes());
637
638        // Bob can now use the secret to claim funds on another chain
639    }
640
641    #[test]
642    fn test_public_key_serialization() {
643        let signer = AdaptorSigner::new();
644        let pubkey = signer.public_key();
645
646        let bytes = pubkey.to_bytes();
647        let recovered = AdaptorPublicKey::from_bytes(&bytes).unwrap();
648
649        assert_eq!(pubkey.to_bytes(), recovered.to_bytes());
650    }
651
652    #[test]
653    fn test_deterministic_completion() {
654        let secret = AdaptorSecret::random();
655        let _adaptor = secret.to_point();
656
657        let signer = AdaptorSigner::new();
658        let message = b"Test message";
659
660        let pre_sig = signer
661            .create_pre_signature_with_secret(message, &secret)
662            .unwrap();
663
664        // Complete the same pre-signature twice
665        let sig1 = complete_signature(&pre_sig, &secret).unwrap();
666        let sig2 = complete_signature(&pre_sig, &secret).unwrap();
667
668        // Should produce identical signatures
669        assert_eq!(sig1.to_bytes(), sig2.to_bytes());
670    }
671}