Browse Source

Introduce oracle module

no-contract-setup-message
Lucas Soriano del Pino 3 years ago
parent
commit
ea3a54ff36
No known key found for this signature in database GPG Key ID: EE611E973A1530E7
  1. 30
      cfd_protocol/src/lib.rs
  2. 78
      cfd_protocol/src/oracle.rs
  3. 15
      cfd_protocol/src/oracle/bip340_hash.rs
  4. 43
      cfd_protocol/src/oracle/secp_utils.rs
  5. 66
      cfd_protocol/tests/cfds.rs

30
cfd_protocol/src/lib.rs

@ -3,7 +3,7 @@ pub use secp256k1_zkp;
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use bdk::bitcoin::hashes::hex::ToHex; use bdk::bitcoin::hashes::hex::ToHex;
use bdk::bitcoin::hashes::*; use bdk::bitcoin::hashes::Hash;
use bdk::bitcoin::util::bip143::SigHashCache; use bdk::bitcoin::util::bip143::SigHashCache;
use bdk::bitcoin::util::psbt::{Global, PartiallySignedTransaction}; use bdk::bitcoin::util::psbt::{Global, PartiallySignedTransaction};
use bdk::bitcoin::{ use bdk::bitcoin::{
@ -16,12 +16,12 @@ use bdk::miniscript::DescriptorTrait;
use bdk::wallet::AddressIndex; use bdk::wallet::AddressIndex;
use bdk::FeeRate; use bdk::FeeRate;
use itertools::Itertools; use itertools::Itertools;
use secp256k1_zkp::bitcoin_hashes::sha256;
use secp256k1_zkp::{schnorrsig, EcdsaAdaptorSignature, SecretKey, Signature, SECP256K1}; use secp256k1_zkp::{schnorrsig, EcdsaAdaptorSignature, SecretKey, Signature, SECP256K1};
use std::collections::HashMap; use std::collections::HashMap;
use std::iter::FromIterator; use std::iter::FromIterator;
pub mod interval; pub mod interval;
pub mod oracle;
/// In satoshi per vbyte. /// In satoshi per vbyte.
const SATS_PER_VBYTE: f64 = 1.0; const SATS_PER_VBYTE: f64 = 1.0;
@ -530,20 +530,6 @@ impl Payout {
} }
} }
const BIP340_MIDSTATE: [u8; 32] = [
0x9c, 0xec, 0xba, 0x11, 0x23, 0x92, 0x53, 0x81, 0x11, 0x67, 0x91, 0x12, 0xd1, 0x62, 0x7e, 0x0f,
0x97, 0xc8, 0x75, 0x50, 0x00, 0x3c, 0xc7, 0x65, 0x90, 0xf6, 0x11, 0x64, 0x33, 0xe9, 0xb6, 0x6a,
];
sha256t_hash_newtype!(
BIP340Hash,
BIP340HashTag,
BIP340_MIDSTATE,
64,
doc = "bip340 hash",
true
);
/// Compute a signature point for the given oracle public key, announcement nonce public key and /// Compute a signature point for the given oracle public key, announcement nonce public key and
/// message. /// message.
fn compute_signature_point( fn compute_signature_point(
@ -558,17 +544,7 @@ fn compute_signature_point(
Ok(secp256k1_zkp::PublicKey::from_slice(&buf)?) Ok(secp256k1_zkp::PublicKey::from_slice(&buf)?)
} }
let hash = { let hash = oracle::msg_hash(oracle_pk, nonce_pk, msg);
let mut buf = Vec::<u8>::new();
buf.extend(&nonce_pk.serialize());
buf.extend(&oracle_pk.serialize());
buf.extend(
secp256k1_zkp::Message::from_hashed_data::<sha256::Hash>(msg)
.as_ref()
.to_vec(),
);
BIP340Hash::hash(&buf).into_inner().to_vec()
};
let mut oracle_pk = schnorr_pubkey_to_pubkey(oracle_pk)?; let mut oracle_pk = schnorr_pubkey_to_pubkey(oracle_pk)?;
oracle_pk.mul_assign(SECP256K1, &hash)?; oracle_pk.mul_assign(SECP256K1, &hash)?;
let nonce_pk = schnorr_pubkey_to_pubkey(nonce_pk)?; let nonce_pk = schnorr_pubkey_to_pubkey(nonce_pk)?;

78
cfd_protocol/src/oracle.rs

@ -0,0 +1,78 @@
pub use secp256k1_zkp::*;
use bdk::bitcoin::hashes::Hash;
use bip340_hash::Bip340Hash;
use rand::{CryptoRng, RngCore};
use secp256k1_zkp::bitcoin_hashes::sha256;
use secp256k1_zkp::{schnorrsig, SecretKey};
mod bip340_hash;
mod secp_utils;
/// Sign `msg` with the oracle's `key_pair` and a pre-computed `nonce`
/// whose corresponding public key was included in a previous
/// announcement.
pub fn attest(
key_pair: &schnorrsig::KeyPair,
nonce: &SecretKey,
msg: &[u8],
) -> schnorrsig::Signature {
let msg = secp256k1_zkp::Message::from_hashed_data::<sha256::Hash>(msg);
secp_utils::schnorr_sign_with_nonce(&msg, key_pair, nonce)
}
pub fn nonce<R>(rng: &mut R) -> (SecretKey, schnorrsig::PublicKey)
where
R: RngCore + CryptoRng,
{
let nonce = SecretKey::new(rng);
let key_pair = schnorrsig::KeyPair::from_secret_key(SECP256K1, nonce);
let nonce_pk = schnorrsig::PublicKey::from_keypair(SECP256K1, &key_pair);
(nonce, nonce_pk)
}
pub fn msg_hash(
pk: &schnorrsig::PublicKey,
nonce_pk: &schnorrsig::PublicKey,
msg: &[u8],
) -> Vec<u8> {
let mut buf = Vec::<u8>::new();
buf.extend(&nonce_pk.serialize());
buf.extend(&pk.serialize());
buf.extend(
secp256k1_zkp::Message::from_hashed_data::<sha256::Hash>(msg)
.as_ref()
.to_vec(),
);
Bip340Hash::hash(&buf).into_inner().to_vec()
}
#[cfg(test)]
mod tests {
use super::*;
use rand::thread_rng;
fn verify(sig: &schnorrsig::Signature, msg: &[u8], pk: &schnorrsig::PublicKey) -> bool {
let msg = secp256k1_zkp::Message::from_hashed_data::<sha256::Hash>(msg);
SECP256K1.schnorrsig_verify(sig, &msg, pk).is_ok()
}
#[test]
fn attest_and_verify() {
let mut rng = thread_rng();
let key_pair = schnorrsig::KeyPair::new(SECP256K1, &mut rng);
let pk = schnorrsig::PublicKey::from_keypair(SECP256K1, &key_pair);
let (nonce, _nonce_pk) = nonce(&mut rng);
let msg = b"hello world";
let sig = attest(&key_pair, &nonce, msg);
assert!(verify(&sig, msg, &pk));
}
}

15
cfd_protocol/src/oracle/bip340_hash.rs

@ -0,0 +1,15 @@
use bdk::bitcoin::hashes::*;
sha256t_hash_newtype!(
Bip340Hash,
Bip340HashTag,
BIP340_MIDSTATE,
64,
doc = "bip340 hash",
true
);
const BIP340_MIDSTATE: [u8; 32] = [
0x9c, 0xec, 0xba, 0x11, 0x23, 0x92, 0x53, 0x81, 0x11, 0x67, 0x91, 0x12, 0xd1, 0x62, 0x7e, 0x0f,
0x97, 0xc8, 0x75, 0x50, 0x00, 0x3c, 0xc7, 0x65, 0x90, 0xf6, 0x11, 0x64, 0x33, 0xe9, 0xb6, 0x6a,
];

43
cfd_protocol/src/oracle/secp_utils.rs

@ -0,0 +1,43 @@
use secp256k1_zkp::secp256k1_zkp_sys::types::c_void;
use secp256k1_zkp::secp256k1_zkp_sys::CPtr;
use secp256k1_zkp::{schnorrsig, SecretKey, SECP256K1};
use std::os::raw::{c_int, c_uchar};
use std::ptr;
/// Create a Schnorr signature using the provided nonce instead of generating one.
pub fn schnorr_sign_with_nonce(
msg: &secp256k1_zkp::Message,
keypair: &schnorrsig::KeyPair,
nonce: &SecretKey,
) -> schnorrsig::Signature {
unsafe {
let mut sig = [0u8; secp256k1_zkp::constants::SCHNORRSIG_SIGNATURE_SIZE];
assert_eq!(
1,
secp256k1_zkp::ffi::secp256k1_schnorrsig_sign(
*SECP256K1.ctx(),
sig.as_mut_c_ptr(),
msg.as_c_ptr(),
keypair.as_ptr(),
Some(constant_nonce_fn),
nonce.as_c_ptr() as *const c_void
)
);
schnorrsig::Signature::from_slice(&sig).unwrap()
}
}
extern "C" fn constant_nonce_fn(
nonce32: *mut c_uchar,
_msg32: *const c_uchar,
_key32: *const c_uchar,
_xonly_pk32: *const c_uchar,
_algo16: *const c_uchar,
data: *mut c_void,
) -> c_int {
unsafe {
ptr::copy_nonoverlapping(data as *const c_uchar, nonce32, 32);
}
1
}

66
cfd_protocol/tests/cfds.rs

@ -10,12 +10,11 @@ use bitcoin::Txid;
use cfd_protocol::interval::Interval; use cfd_protocol::interval::Interval;
use cfd_protocol::{ use cfd_protocol::{
commit_descriptor, compute_adaptor_point, create_cfd_transactions, finalize_spend_transaction, commit_descriptor, compute_adaptor_point, create_cfd_transactions, finalize_spend_transaction,
lock_descriptor, punish_transaction, renew_cfd_transactions, spending_tx_sighash, lock_descriptor, oracle, punish_transaction, renew_cfd_transactions, spending_tx_sighash,
CfdTransactions, Payout, PunishParams, TransactionExt, WalletExt, CfdTransactions, Payout, PunishParams, TransactionExt, WalletExt,
}; };
use rand::{CryptoRng, RngCore, SeedableRng}; use rand::{CryptoRng, RngCore, SeedableRng};
use rand_chacha::ChaChaRng; use rand_chacha::ChaChaRng;
use secp256k1_zkp::bitcoin_hashes::sha256;
use secp256k1_zkp::{schnorrsig, EcdsaAdaptorSignature, SecretKey, Signature, SECP256K1}; use secp256k1_zkp::{schnorrsig, EcdsaAdaptorSignature, SecretKey, Signature, SECP256K1};
#[test] #[test]
@ -844,10 +843,7 @@ impl Oracle {
fn attest(&self, event: &Event, msgs: &[&[u8]]) -> Vec<schnorrsig::Signature> { fn attest(&self, event: &Event, msgs: &[&[u8]]) -> Vec<schnorrsig::Signature> {
msgs.iter() msgs.iter()
.zip(&event.nonces) .zip(&event.nonces)
.map(|(msg, nonce)| { .map(|(msg, nonce)| oracle::attest(&self.key_pair, nonce, msg))
let msg = secp256k1_zkp::Message::from_hashed_data::<sha256::Hash>(msg);
secp_utils::schnorr_sign_with_nonce(&msg, &self.key_pair, nonce)
})
.collect() .collect()
} }
} }
@ -877,16 +873,7 @@ impl Event {
where where
R: RngCore + CryptoRng, R: RngCore + CryptoRng,
{ {
let (nonces, nonce_pks) = (0..20) let (nonces, nonce_pks) = (0..20).map(|_| oracle::nonce(rng)).unzip();
.map(|_| {
let nonce = SecretKey::new(rng);
let key_pair = schnorrsig::KeyPair::from_secret_key(SECP256K1, nonce);
let nonce_pk = schnorrsig::PublicKey::from_keypair(SECP256K1, &key_pair);
(nonce, nonce_pk)
})
.unzip();
Self { nonces, nonce_pks } Self { nonces, nonce_pks }
} }
@ -935,50 +922,3 @@ fn schnorrsig_decompose(signature: &schnorrsig::Signature) -> (schnorrsig::Publi
(nonce_pk, s) (nonce_pk, s)
} }
mod secp_utils {
use super::*;
use secp256k1_zkp::secp256k1_zkp_sys::types::c_void;
use secp256k1_zkp::secp256k1_zkp_sys::CPtr;
use std::os::raw::{c_int, c_uchar};
use std::ptr;
/// Create a Schnorr signature using the provided nonce instead of generating one.
pub fn schnorr_sign_with_nonce(
msg: &secp256k1_zkp::Message,
keypair: &schnorrsig::KeyPair,
nonce: &SecretKey,
) -> schnorrsig::Signature {
unsafe {
let mut sig = [0u8; secp256k1_zkp::constants::SCHNORRSIG_SIGNATURE_SIZE];
assert_eq!(
1,
secp256k1_zkp::ffi::secp256k1_schnorrsig_sign(
*SECP256K1.ctx(),
sig.as_mut_c_ptr(),
msg.as_c_ptr(),
keypair.as_ptr(),
Some(constant_nonce_fn),
nonce.as_c_ptr() as *const c_void
)
);
schnorrsig::Signature::from_slice(&sig).unwrap()
}
}
extern "C" fn constant_nonce_fn(
nonce32: *mut c_uchar,
_msg32: *const c_uchar,
_key32: *const c_uchar,
_xonly_pk32: *const c_uchar,
_algo16: *const c_uchar,
data: *mut c_void,
) -> c_int {
unsafe {
ptr::copy_nonoverlapping(data as *const c_uchar, nonce32, 32);
}
1
}
}

Loading…
Cancel
Save