spark_cryptography/
adaptor_signature.rs

1// use bitcoin::secp256k1::{Message, PublicKey, Secp256k1, SecretKey, schnorr::Signature};
2// use elliptic_curve::{PrimeField, generic_array::GenericArray, group::GroupEncoding};
3// use hmac::Mac;
4// use k256::ProjectivePoint;
5// use k256::schnorr::{
6//     SigningKey, VerifyingKey,
7//     signature::{Signer, Verifier},
8// };
9// use rand::thread_rng;
10// use sha2::{Digest, Sha256};
11
12// #[derive(Debug)]
13// pub struct AdaptorSignature {
14//     pub signature: [u8; 64],
15//     pub adaptor_private_key: [u8; 32],
16// }
17
18// const MOCK_SECRET_KEY: [u8; 32] = [
19//     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
20//     0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
21// ];
22
23// const MOCK_ADAPTOR_KEY: [u8; 32] = [
24//     0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
25//     0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
26// ];
27
28// pub fn generate_adaptor_from_signature(
29//     signature: &[u8; 64],
30// ) -> Result<AdaptorSignature, Box<dyn std::error::Error>> {
31//     let secp = Secp256k1::new();
32//     let mut rng = thread_rng();
33
34//     // Generate random adaptor private key
35//     let adaptor_private_key = SecretKey::new(&mut rng);
36
37//     // Parse the original signature
38//     let sig = Signature::from_slice(signature)?;
39
40//     // Extract r and s components
41//     let r = sig[..32].to_vec();
42//     let s = sig[32..].to_vec();
43
44//     let s_ga = GenericArray::from_slice(&s);
45//     let adaptor_private_key_ga = GenericArray::from_slice(adaptor_private_key.as_ref());
46
47//     // Convert s to scalar
48//     let s_scalar = k256::Scalar::from_repr(*s_ga).unwrap();
49//     let t_scalar = k256::Scalar::from_repr(*adaptor_private_key_ga).unwrap();
50
51//     // Calculate s - adaptor_private_key
52//     let new_s = s_scalar - t_scalar;
53
54//     // Create new signature
55//     let mut new_signature = [0u8; 64];
56//     new_signature[..32].copy_from_slice(&r);
57//     new_signature[32..].copy_from_slice(&new_s.to_bytes());
58
59//     Ok(AdaptorSignature {
60//         signature: new_signature,
61//         adaptor_private_key: adaptor_private_key.secret_bytes(),
62//     })
63// }
64
65// pub fn validate_outbound_adaptor_signature(
66//     pubkey: &[u8],
67//     message: &[u8],
68//     signature: &[u8],
69//     adaptor_pubkey: &[u8],
70// ) -> Result<bool, Box<dyn std::error::Error>> {
71//     schnorr_verify_with_adaptor(signature, message, pubkey, adaptor_pubkey, false)
72// }
73
74// pub fn apply_adaptor_to_signature(
75//     pubkey: &[u8],
76//     message: &[u8],
77//     signature: &[u8],
78//     adaptor_private_key: &[u8],
79// ) -> Result<[u8; 64], Box<dyn std::error::Error>> {
80//     let secp = Secp256k1::new();
81
82//     // Parse the signature
83//     let sig: [u8; 64] = signature
84//         .try_into()
85//         .map_err(|_| "Invalid signature length")?;
86//     let (r, s) = sig.split_at(32);
87
88//     // let r_ga = GenericArray::from_slice(r);
89//     let s_ga = GenericArray::from_slice(s);
90//     let adaptor_private_key_ga = GenericArray::from_slice(adaptor_private_key);
91
92//     // Convert to scalars
93//     let s_scalar = k256::Scalar::from_repr(*s_ga).unwrap();
94//     let t_scalar = k256::Scalar::from_repr(*adaptor_private_key_ga).unwrap();
95
96//     // Try adding adaptor first
97//     let new_s = s_scalar + t_scalar;
98//     let mut new_sig = [0u8; 64];
99//     new_sig[..32].copy_from_slice(r);
100//     new_sig[32..].copy_from_slice(&new_s.to_bytes());
101
102//     // Verify the signature
103//     let msg = Message::from_slice(message)?;
104//     let pk = PublicKey::from_slice(pubkey)?;
105
106//     if secp
107//         .verify_schnorr(
108//             &bitcoin::secp256k1::schnorr::Signature::from_slice(&new_sig)?,
109//             &msg,
110//             &pk.x_only_public_key().0,
111//         )
112//         .is_ok()
113//     {
114//         return Ok(new_sig);
115//     }
116
117//     // If adding didn't work, try subtracting
118//     let alt_s = s_scalar - t_scalar;
119//     let mut alt_sig = [0u8; 64];
120//     alt_sig[..32].copy_from_slice(r);
121//     alt_sig[32..].copy_from_slice(&alt_s.to_bytes());
122
123//     if secp
124//         .verify_schnorr(
125//             &bitcoin::secp256k1::schnorr::Signature::from_slice(&alt_sig)?,
126//             &msg,
127//             &pk.x_only_public_key().0,
128//         )
129//         .is_ok()
130//     {
131//         return Ok(alt_sig);
132//     }
133
134//     Err("Cannot apply adaptor to signature".into())
135// }
136
137// fn schnorr_verify_with_adaptor(
138//     signature: &[u8],
139//     message: &[u8],
140//     pubkey: &[u8],
141//     adaptor_pubkey: &[u8],
142//     inbound: bool,
143// ) -> Result<bool, Box<dyn std::error::Error>> {
144//     // Verify message length
145//     if message.len() != 32 {
146//         return Err(format!("wrong size for message (got {}, want 32)", message.len()).into());
147//     }
148
149//     // Parse public key
150//     let pk = PublicKey::from_slice(pubkey)?;
151//     let pk_bytes = pk.serialize();
152//     let pk_ga = GenericArray::from_slice(pk_bytes.as_slice());
153//     let pk_point = ProjectivePoint::from_bytes(pk_ga).unwrap();
154
155//     // Parse signature
156//     if signature.len() != 64 {
157//         return Err(format!("wrong signature length: {}", signature.len()).into());
158//     }
159
160//     let (r_bytes, s_bytes) = signature.split_at(32);
161
162//     // Compute tagged hash for challenge
163//     let mut hasher = Sha256::new();
164//     hasher.update(b"BIP0340/challenge");
165//     hasher.update(r_bytes);
166//     hasher.update(&pk.serialize()[1..]); // Skip first byte (parity)
167//     hasher.update(message);
168//     let e = hasher.finalize();
169
170//     // Convert challenge to scalar
171//     let e_ga = GenericArray::from_slice(e.as_slice());
172//     let e_scalar = k256::Scalar::from_repr(*e_ga).unwrap();
173//     let neg_e = -e_scalar;
174
175//     // Calculate R = sG - eP
176//     let s_ga = GenericArray::from_slice(s_bytes);
177//     let s_scalar = k256::Scalar::from_repr(*s_ga).unwrap();
178//     let base_point = ProjectivePoint::GENERATOR;
179//     let r_point = (base_point * s_scalar) + (pk_point * neg_e);
180
181//     // Add adaptor public key
182//     let adaptor_ga = GenericArray::from_slice(adaptor_pubkey);
183//     let adaptor_point = ProjectivePoint::from_bytes(adaptor_ga).unwrap();
184//     let new_r = r_point + adaptor_point;
185
186//     // TODO: Check for point at infinity
187//     // if !inbound && new_r.is_identity().into() {
188//     //     return Err("calculated R point is the point at infinity".into());
189//     // }
190
191//     // TODO: Convert to affine and check y coordinate parity
192//     // let new_r_affine = new_r.to_affine();
193//     // if new_r_affine.y().is_odd().into() {
194//     //     return Err("calculated R y-value is odd".into());
195//     // }
196
197//     // TODO: Check if x coordinate matches r
198//     let r_ga = GenericArray::from_slice(r_bytes);
199//     let r_scalar = k256::Scalar::from_repr(*r_ga).unwrap();
200//     // if new_r.x() != &r_scalar.into() {
201//     //     return Err("calculated R point was not given R".into());
202//     // }
203
204//     Ok(true)
205// }
206
207// #[cfg(test)]
208// mod tests {
209//     use std::str::FromStr;
210
211//     use super::*;
212//     use k256::ecdsa::signature::SignerMut;
213//     use schnorr_fun::{Schnorr, fun::nonce::Deterministic};
214//     use secp256k1::Keypair;
215
216//     #[test]
217//     fn test_adaptor_signature() {
218//         let secp = Secp256k1::new();
219
220//         // Use mock secret key
221//         println!(
222//             "RUST: Using mock secret key: {:?}",
223//             hex::encode(&MOCK_SECRET_KEY)
224//         );
225//         let secret_key = SecretKey::from_slice(&MOCK_SECRET_KEY).unwrap();
226//         let public_key = PublicKey::from_secret_key(&secp, &secret_key);
227//         println!(
228//             "RUST: Generated public key: {:?}",
229//             hex::encode(&public_key.serialize())
230//         );
231//         // generate Schnorr verifying key
232//         let verifying_key = public_key.x_only_public_key().0;
233//         println!(
234//             "RUST: Schnorr verifying == xonly pubkey: {:?}",
235//             hex::encode(&verifying_key.serialize())
236//         );
237
238//         // Create test message and hash
239//         let message = b"test";
240//         println!("RUST: Test message: {:?}", hex::encode(&message));
241//         let mut hasher = Sha256::new();
242//         hasher.update(message);
243//         let msg_hash = hasher.finalize();
244//         println!("RUST: Message hash: {:?}", hex::encode(&msg_hash));
245
246//         // Create original signature
247//         let msg = Message::from_slice(&msg_hash).unwrap();
248//         let keypair = Keypair::from_secret_key(&secp, &secret_key);
249
250//         let signature = Signature::from_str("b28a65d8651818ea04cfdf945455d64bbd7bac068532289a8cc0801a9ed283046159052e7ec6972cc113b2d6bc17883d5d1d4e12a4563f05b220e7b8533342e3")
251//             .unwrap();
252//         let is_valid = secp
253//             .verify_schnorr(
254//                 &signature,
255//                 &msg,
256//                 &keypair.public_key().x_only_public_key().0,
257//             )
258//             .is_ok();
259
260//         println!("is_valid: {}", is_valid);
261//     }
262// }
263
264// const RFC6979_EXTRA_DATA: &[u8] = b"BIP-340";
265
266// fn rfc6979_generate_k(
267//     priv_key: &[u8],
268//     msg_hash: &[u8],
269//     extra_data: &[u8],
270//     iteration: u32,
271// ) -> [u8; 32] {
272//     type HmacSha256 = hmac::Hmac<sha2::Sha256>;
273
274//     let mut v = [0x01; 32];
275//     let mut k = [0x00; 32];
276
277//     // Step A
278//     let mut hmac = HmacSha256::new_from_slice(&k).unwrap();
279//     hmac.update(&v);
280//     hmac.update(&[0x00]);
281//     hmac.update(priv_key);
282//     hmac.update(msg_hash);
283//     hmac.update(extra_data);
284//     hmac.update(&iteration.to_be_bytes());
285//     k = hmac.finalize().into_bytes().try_into().unwrap();
286
287//     // Step B
288//     let mut hmac = HmacSha256::new_from_slice(&k).unwrap();
289//     hmac.update(&v);
290//     v = hmac.finalize().into_bytes().try_into().unwrap();
291
292//     // Step C
293//     let mut hmac = HmacSha256::new_from_slice(&k).unwrap();
294//     hmac.update(&v);
295//     hmac.update(&[0x01]);
296//     hmac.update(priv_key);
297//     hmac.update(msg_hash);
298//     hmac.update(extra_data);
299//     hmac.update(&iteration.to_be_bytes());
300//     k = hmac.finalize().into_bytes().try_into().unwrap();
301
302//     // Step D
303//     let mut hmac = HmacSha256::new_from_slice(&k).unwrap();
304//     hmac.update(&v);
305//     v = hmac.finalize().into_bytes().try_into().unwrap();
306
307//     // Step E
308//     let mut hmac = HmacSha256::new_from_slice(&k).unwrap();
309//     hmac.update(&v);
310//     v = hmac.finalize().into_bytes().try_into().unwrap();
311
312//     v
313// }
314
315// pub fn sign_schnorr_btcd_compatible(secret_key: &[u8; 32], msg: &[u8]) -> [u8; 64] {
316//     // Hash message
317//     let mut hasher = Sha256::new();
318//     hasher.update(msg);
319//     let msg_hash = hasher.finalize();
320
321//     // Generate RFC6979 nonce matching btcd (with iteration 0)
322//     let aux_rand = rfc6979_generate_k(secret_key, &msg_hash, RFC6979_EXTRA_DATA, 0);
323
324//     // Create signing key
325//     let signing_key = SigningKey::from_bytes(secret_key).unwrap();
326
327//     // Sign using the generated aux_rand
328//     let sig = signing_key
329//         .sign_prehash_with_aux_rand(&msg_hash.into(), &aux_rand)
330//         .unwrap();
331
332//     sig.to_bytes()
333// }
334
335use bitcoin::secp256k1::{schnorr::Signature, Message, PublicKey, Secp256k1, SecretKey};
336use elliptic_curve::{generic_array::GenericArray, group::GroupEncoding, PrimeField};
337use k256::elliptic_curve::point::AffineCoordinates;
338use k256::ProjectivePoint;
339
340use rand::thread_rng;
341use sha2::{Digest, Sha256};
342
343#[derive(Debug)]
344pub struct AdaptorSignature {
345    pub signature: [u8; 64],
346    pub adaptor_private_key: [u8; 32],
347}
348
349pub fn generate_adaptor_from_signature(
350    signature: &[u8; 64],
351) -> Result<AdaptorSignature, Box<dyn std::error::Error>> {
352    let mut rng = thread_rng();
353
354    // Generate random adaptor private key
355    let adaptor_private_key = SecretKey::new(&mut rng);
356
357    // Parse the original signature
358    let sig = Signature::from_slice(signature)?;
359
360    // Extract r and s components
361    let r = sig[..32].to_vec();
362    let s = sig[32..].to_vec();
363
364    let s_ga = GenericArray::from_slice(&s);
365    let adaptor_private_key_ga = GenericArray::from_slice(adaptor_private_key.as_ref());
366
367    // Convert s to scalar
368    let s_scalar = k256::Scalar::from_repr(*s_ga).unwrap();
369    let t_scalar = k256::Scalar::from_repr(*adaptor_private_key_ga).unwrap();
370
371    // Calculate s - adaptor_private_key
372    let new_s = s_scalar - t_scalar;
373
374    // Create new signature
375    let mut new_signature = [0u8; 64];
376    new_signature[..32].copy_from_slice(&r);
377    new_signature[32..].copy_from_slice(&new_s.to_bytes());
378
379    Ok(AdaptorSignature {
380        signature: new_signature,
381        adaptor_private_key: adaptor_private_key.secret_bytes(),
382    })
383}
384
385pub fn validate_outbound_adaptor_signature(
386    pubkey: &[u8],
387    message: &[u8],
388    signature: &[u8],
389    adaptor_pubkey: &[u8],
390) -> Result<bool, Box<dyn std::error::Error>> {
391    schnorr_verify_with_adaptor(signature, message, pubkey, adaptor_pubkey, false)
392}
393
394pub fn apply_adaptor_to_signature(
395    pubkey: &[u8],
396    message: &[u8],
397    signature: &[u8],
398    adaptor_private_key: &[u8],
399) -> Result<[u8; 64], Box<dyn std::error::Error>> {
400    let secp = Secp256k1::new();
401
402    // Parse the signature
403    let sig: [u8; 64] = signature
404        .try_into()
405        .map_err(|_| "Invalid signature length")?;
406    let (r, s) = sig.split_at(32);
407
408    // let r_ga = GenericArray::from_slice(r);
409    let s_ga = GenericArray::from_slice(s);
410    let adaptor_private_key_ga = GenericArray::from_slice(adaptor_private_key);
411
412    // Convert to scalars
413    let s_scalar = k256::Scalar::from_repr(*s_ga).unwrap();
414    let t_scalar = k256::Scalar::from_repr(*adaptor_private_key_ga).unwrap();
415
416    // Try adding adaptor first
417    let new_s = s_scalar + t_scalar;
418    let mut new_sig = [0u8; 64];
419    new_sig[..32].copy_from_slice(r);
420    new_sig[32..].copy_from_slice(&new_s.to_bytes());
421
422    // Verify the signature
423    let msg = Message::from_digest_slice(message).map_err(|_| "Invalid message")?;
424    let pk = PublicKey::from_slice(pubkey).map_err(|_| "Invalid public key")?;
425
426    if secp
427        .verify_schnorr(
428            &bitcoin::secp256k1::schnorr::Signature::from_slice(&new_sig)?,
429            &msg,
430            &pk.x_only_public_key().0,
431        )
432        .is_ok()
433    {
434        return Ok(new_sig);
435    }
436
437    // If adding didn't work, try subtracting
438    let alt_s = s_scalar - t_scalar;
439    let mut alt_sig = [0u8; 64];
440    alt_sig[..32].copy_from_slice(r);
441    alt_sig[32..].copy_from_slice(&alt_s.to_bytes());
442
443    if secp
444        .verify_schnorr(
445            &bitcoin::secp256k1::schnorr::Signature::from_slice(&alt_sig)?,
446            &msg,
447            &pk.x_only_public_key().0,
448        )
449        .is_ok()
450    {
451        return Ok(alt_sig);
452    }
453
454    Err("Cannot apply adaptor to signature".into())
455}
456
457pub fn generate_signature_from_existing_adaptor(
458    signature: &[u8],
459    adaptor_private_key: &[u8],
460) -> Result<[u8; 64], Box<dyn std::error::Error>> {
461    // Parse signature
462    if signature.len() != 64 {
463        return Err(format!("wrong signature length: {}", signature.len()).into());
464    }
465
466    let (r, s) = signature.split_at(32);
467    let s_ga = GenericArray::from_slice(s);
468    let adaptor_private_key_ga = GenericArray::from_slice(adaptor_private_key);
469
470    // Convert to scalars
471    let s_scalar = k256::Scalar::from_repr(*s_ga).unwrap();
472    let mut t_scalar = k256::Scalar::from_repr(*adaptor_private_key_ga).unwrap();
473
474    // Negate t
475    t_scalar = -t_scalar;
476
477    // Add negated t to s
478    let new_s = s_scalar + t_scalar;
479
480    // Create new signature
481    let mut new_sig = [0u8; 64];
482    new_sig[..32].copy_from_slice(r);
483    new_sig[32..].copy_from_slice(&new_s.to_bytes());
484
485    Ok(new_sig)
486}
487
488fn schnorr_verify_with_adaptor(
489    signature: &[u8],
490    message: &[u8],
491    pubkey: &[u8],
492    adaptor_pubkey: &[u8],
493    inbound: bool,
494) -> Result<bool, Box<dyn std::error::Error>> {
495    // Verify message length
496    if message.len() != 32 {
497        return Err(format!("wrong size for message (got {}, want 32)", message.len()).into());
498    }
499
500    // Parse public key
501    let pk = PublicKey::from_slice(pubkey)?;
502    let pk_bytes = pk.serialize();
503    let pk_ga = GenericArray::from_slice(pk_bytes.as_slice());
504    let pk_point = ProjectivePoint::from_bytes(pk_ga).unwrap();
505
506    // Parse signature
507    if signature.len() != 64 {
508        return Err(format!("wrong signature length: {}", signature.len()).into());
509    }
510
511    let (r_bytes, s_bytes) = signature.split_at(32);
512
513    // Compute tagged hash for challenge
514    let mut hasher = Sha256::new();
515    hasher.update(b"BIP0340/chllenge");
516    hasher.update(r_bytes);
517    hasher.update(&pk.serialize()[1..]); // Skip first byte (parity)
518    hasher.update(message);
519    let e = hasher.finalize();
520
521    // Convert challenge to scalar
522    let e_ga = GenericArray::from_slice(e.as_slice());
523    let e_scalar = k256::Scalar::from_repr(*e_ga).unwrap();
524    let neg_e = -e_scalar;
525
526    // Calculate R = sG - eP
527    let s_ga = GenericArray::from_slice(s_bytes);
528    let s_scalar = k256::Scalar::from_repr(*s_ga).unwrap();
529    let base_point = ProjectivePoint::GENERATOR;
530    let r_point = (base_point * s_scalar) + (pk_point * neg_e);
531
532    // Add adaptor public key
533    let adaptor_ga = GenericArray::from_slice(adaptor_pubkey);
534    let adaptor_point = ProjectivePoint::from_bytes(adaptor_ga).unwrap();
535    let new_r = r_point + adaptor_point;
536
537    // TODO: Check for point at infinity
538    if !inbound && new_r == ProjectivePoint::IDENTITY {
539        return Err("calculated R point is the point at infinity".into());
540    }
541
542    // TODO: Convert to affine and check y coordinate parity
543    let new_r_affine = new_r.to_affine();
544    // if new_r_affine.y().is_odd().into() {
545    //     return Err("calculated R y-value is odd".into());
546    // }
547
548    // TODO: Check if x coordinate matches r
549    let r_ga = GenericArray::from_slice(r_bytes);
550    let r_scalar = k256::Scalar::from_repr(*r_ga).unwrap();
551    let new_r_x = new_r_affine.x();
552    if new_r_x != r_scalar.to_bytes() {
553        return Err("calculated R point x-coordinate does not match r".into());
554    }
555
556    Ok(true)
557}
558
559#[cfg(test)]
560mod tests {
561    use secp256k1::Keypair;
562
563    use super::*;
564
565    #[test]
566    #[ignore]
567    fn test_adaptor_signature_flow() {
568        let secp = Secp256k1::new();
569        let mut rng = thread_rng();
570
571        // Generate test keys
572        let secret_key = SecretKey::new(&mut rng);
573        let public_key = PublicKey::from_secret_key(&secp, &secret_key);
574
575        // Create test message
576        let message = b"Hello, world!";
577        let msg_hash = Sha256::digest(message);
578
579        // Create original signature
580        let msg = Message::from_digest_slice(&msg_hash).unwrap();
581        let keypair = Keypair::from_secret_key(&secp, &secret_key);
582        let sig = secp.sign_schnorr(&msg, &keypair);
583
584        // Generate adaptor signature
585        let adaptor_result = generate_adaptor_from_signature(&sig.as_ref()).unwrap();
586
587        // Validate adaptor signature
588        let adaptor_pubkey = PublicKey::from_secret_key(
589            &secp,
590            &SecretKey::from_slice(&adaptor_result.adaptor_private_key).unwrap(),
591        );
592
593        let is_valid = validate_outbound_adaptor_signature(
594            &public_key.serialize(),
595            &msg_hash,
596            &adaptor_result.signature,
597            &adaptor_pubkey.serialize(),
598        )
599        .unwrap();
600
601        assert!(is_valid);
602
603        // Apply adaptor to signature
604        let final_sig = apply_adaptor_to_signature(
605            &public_key.serialize(),
606            &msg_hash,
607            &adaptor_result.signature,
608            &adaptor_result.adaptor_private_key,
609        )
610        .unwrap();
611
612        // Verify final signature
613        assert!(secp
614            .verify_schnorr(
615                &bitcoin::secp256k1::schnorr::Signature::from_slice(&final_sig).unwrap(),
616                &msg,
617                &public_key.x_only_public_key().0
618            )
619            .is_ok());
620    }
621}