From 0911eda683a59b8144387abc7b9022f3e71c4245 Mon Sep 17 00:00:00 2001 From: Tibo-lg Date: Fri, 23 Oct 2020 11:23:30 +0900 Subject: [PATCH] Add ecdsa adaptor example --- Cargo.toml | 4 ++ examples/ecdsa_adaptor.rs | 92 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 examples/ecdsa_adaptor.rs diff --git a/Cargo.toml b/Cargo.toml index 12d09c4d3..30e3a28c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,3 +61,7 @@ name = "sign_verify" [[example]] name = "generate_keys" required-features = ["rand"] + +[[example]] +name = "ecdsa_adaptor" +required-features = ["rand", "bitcoin_hashes"] diff --git a/examples/ecdsa_adaptor.rs b/examples/ecdsa_adaptor.rs new file mode 100644 index 000000000..5587385b5 --- /dev/null +++ b/examples/ecdsa_adaptor.rs @@ -0,0 +1,92 @@ +extern crate bitcoin_hashes; +extern crate secp256k1; + +use bitcoin_hashes::sha256; +use secp256k1::rand::rngs::OsRng; +use secp256k1::{ + ecdsa_adaptor::{AdaptorProof, AdaptorSignature}, + key, Message, Secp256k1, +}; + +fn main() { + let secp = Secp256k1::new(); + let mut rng = OsRng::new().expect("OsRng"); + + // Set message to be signed. In practice this would be Bitcoin tx information. + let message = "Hello World"; + let msg_hash = Message::from_hashed_data::(message.as_bytes()); + + // Outcomes: the possible outcome the oracle could sign + let outcomes = ["Head", "Tail"]; + let outcomes_hash: Vec = outcomes + .iter() + .map(|m| Message::from_hashed_data::(m.as_bytes())) + .collect(); + + // Generate oracle key pair and k and R values. + let (oracle_sk, oracle_pk) = secp.generate_bip340_keypair(&mut rng); + let (k_value, r_value) = secp.generate_bip340_keypair(&mut rng); + + // Generate key pairs for Alice and Bob + let (alice_sk, alice_pk) = secp.generate_keypair(&mut rng); + let (bob_sk, bob_pk) = secp.generate_keypair(&mut rng); + + // Compute the signature points: SO_i = R + H(R|P|m_i)*P + let outcomes_sig_points: Vec<::key::PublicKey> = outcomes_hash + .iter() + .map(|h| { + secp.bip340_compute_sig_point(&h, &r_value, &oracle_pk) + .expect("SigPoint") + }) + .collect(); + + // Create adaptor signatures and proofs: + // s'_i = r^-1*(H(m_i)+R'_i*sk) where R'_i = r * SO_i (= r * sO_i * G) + // proof is DLEQ proof + + let alice_adaptor_pairs: Vec<(AdaptorSignature, AdaptorProof)> = outcomes_sig_points + .iter() + .map(|osg| secp.adaptor_sign(&msg_hash, &alice_sk, &osg)) + .collect(); + let bob_adaptor_pairs: Vec<(AdaptorSignature, AdaptorProof)> = outcomes_sig_points + .iter() + .map(|osg| secp.adaptor_sign(&msg_hash, &bob_sk, &osg)) + .collect(); + + // Verify adaptor signatures + // R'_i =? (H(m_i) * G + R'_i * Pubkey) * s'^-1 + // DLEQ proof verification + assert!(alice_adaptor_pairs + .iter() + .zip(outcomes_sig_points.clone()) + .all(|(p, osg)| secp + .adaptor_verify(&msg_hash, &p.0, &alice_pk, &osg, &p.1) + .is_ok())); + + assert!(bob_adaptor_pairs + .iter() + .zip(outcomes_sig_points) + .all(|(p, osg)| secp + .adaptor_verify(&msg_hash, &p.0, &bob_pk, &osg, &p.1) + .is_ok())); + + // Oracle sign + // sO = k_value + H(R|P|m_i) * skO + let oracle_sig = secp + .bip340_sign_with_nonce(&outcomes_hash[0], &oracle_sk, &k_value) + .expect("bip340 sign"); + + // Extract sO + let (_, s_value) = oracle_sig.decompose().unwrap(); + + // Decrypt adaptor signature + // s = s' * sO^-1 = (H(m)+R'*sec)(k_value*sO)^-1 + let decrypted_sig = secp.adaptor_adapt( + &::key::SecretKey::from_slice(s_value.as_ref()).unwrap(), + &alice_adaptor_pairs[0].0, + ); + + // Verify the decrypted ECDSA signature + secp.verify(&msg_hash, &decrypted_sig, &alice_pk) + .expect("Invalid signature"); +}