Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions lib-py/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ pub fn sign_schnorr_with_nonce(msg: String, nonce_sec_hex: String, index: u32) -
.map_err(|e| PyErr::new::<PyException, _>(e))
}

/// Verify a Schnorr signature over a message, using a child key
#[pyfunction]
pub fn verify_schnorr(msg: String, signature_hex: String, index: u32) -> PyResult<bool> {
dlccryptlib::verify_schnorr(&msg, &signature_hex, index)
.map_err(|e| PyErr::new::<PyException, _>(e))
}

/// Combine a number of public keys into one
#[pyfunction]
pub fn combine_pubkeys(keys_hex: String) -> PyResult<String> {
Expand Down Expand Up @@ -182,6 +189,7 @@ fn dlccryptlib_py(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(sign_hash_ecdsa, m)?)?;
m.add_function(wrap_pyfunction!(create_deterministic_nonce, m)?)?;
m.add_function(wrap_pyfunction!(sign_schnorr_with_nonce, m)?)?;
m.add_function(wrap_pyfunction!(verify_schnorr, m)?)?;
m.add_function(wrap_pyfunction!(combine_pubkeys, m)?)?;
m.add_function(wrap_pyfunction!(combine_seckeys, m)?)?;
m.add_function(wrap_pyfunction!(create_cet_adaptor_sigs, m)?)?;
Expand Down
24 changes: 24 additions & 0 deletions src/adaptor_signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,30 @@ fn message_hash(msg: &str) -> Result<Message, String> {
.map_err(|e| e.to_string())
}

/// Verify a Schnorr signature on a message
pub(crate) fn verify_schnorr<S: Signing>(
secp: &Secp256k1<S>,
sig: &SchnorrSignature,
public_key: &XOnlyPublicKey,
msg: &str,
) -> Result<bool, String> {
let msg_hash = sha256::Hash::hash(msg.as_bytes()).to_byte_array();
let msg_msg = Message::from_digest(msg_hash);

let res_num: i32;
unsafe {
res_num = secp256k1_sys::secp256k1_schnorrsig_verify(
secp.ctx().as_ref(),
sig.as_c_ptr(),
msg_msg.as_c_ptr(),
32_usize,
public_key.as_c_ptr(),
);
}

Ok(res_num != 0)
}

pub(crate) fn create_digit_adaptor_sig_point<S: Signing + Verification>(
secp: &Secp256k1<S>,
oracle_pubkey: &PublicKey,
Expand Down
17 changes: 12 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,7 @@ pub fn sign_hash_ecdsa(
Ok(sig.to_lower_hex_string())
}

pub fn create_deterministic_nonce(
event_id: &str,
index: u32,
) -> Result<(String, String), String> {
pub fn create_deterministic_nonce(event_id: &str, index: u32) -> Result<(String, String), String> {
let (sk, pk) = global_lib()
.read()
.unwrap()
Expand All @@ -120,6 +117,17 @@ pub fn sign_schnorr_with_nonce(
Ok(sig.to_string())
}

// Schnorr signature verification
pub fn verify_schnorr(msg: &str, signature_hex: &str, index: u32) -> Result<bool, String> {
let signature = schnorr_sig_from_hex(signature_hex)
.map_err(|e| format!("Error in signature hex string {}", e))?;
let res = global_lib()
.read()
.unwrap()
.verify_schnorr(msg, &signature, index)?;
Ok(res)
}

pub fn combine_pubkeys(keys_hex: &str) -> Result<String, String> {
let keys_split: Vec<_> = keys_hex.split(" ").collect();
let mut keys = Vec::<PublicKey>::with_capacity(keys_split.len());
Expand Down Expand Up @@ -557,4 +565,3 @@ fn error_as_cstr_prefix(error: String) -> *mut c_char {
.unwrap()
.into_raw()
}

13 changes: 12 additions & 1 deletion src/lib_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use crate::adaptor_signature::{
create_cet_adaptor_signatures, create_final_cet_signatures, sign_hash_ecdsa_with_key,
sign_schnorr_with_nonce_sec, verify_cet_adaptor_signatures,
sign_schnorr_with_nonce_sec, verify_cet_adaptor_signatures, verify_schnorr,
};
use crate::hd_wallet_storage::HDWalletStorage;

Expand Down Expand Up @@ -151,6 +151,17 @@ impl Lib {
sign_schnorr_with_nonce_sec(&self.secp, &kp, msg, nonce_sec)
}

/// Verify a Schnorr signature on a message using Schnorr, using a child key
pub(crate) fn verify_schnorr(
&self,
msg: &str,
signature: &SchnorrSignature,
index: u32,
) -> Result<bool, String> {
let pubkey = self.get_child_public_key(index)?.x_only_public_key().0;
verify_schnorr(&self.secp, signature, &pubkey, msg)
}

pub(crate) fn combine_seckeys(secrets: &Vec<SecretKey>) -> Result<SecretKey, String> {
if secrets.len() == 0 {
return Err("At least one key is required".to_string());
Expand Down
34 changes: 31 additions & 3 deletions src/test_lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

use crate::adaptor_signature::verify_ecdsa_signature;
use crate::{
combine_pubkeys, combine_seckeys, create_deterministic_nonce,
get_public_key, init_with_entropy, keypair_from_sec_key_hex,
sign_schnorr_with_nonce, verify_public_key, Lib,
combine_pubkeys, combine_seckeys, create_deterministic_nonce, get_public_key,
init_with_entropy, keypair_from_sec_key_hex, sign_schnorr_with_nonce, verify_public_key,
verify_schnorr, Lib,
};
use bitcoin::hex::FromHex;
use bitcoin::secp256k1::PublicKey;
Expand Down Expand Up @@ -145,6 +145,34 @@ fn test_sign_schnorr_with_nonce() {
assert_eq!(sig3.to_string(), "4578740620e7a2c56eabea07c835dba35e832115930d023d0a7778652fbbf7d97a9f4a207dcb1456f1b0f57c4856085c32c79f4efce81cd276c272190aab5e3c");
}

#[test]
fn test_verify_schnorr() {
let _xpub = init_with_entropy(DUMMY_ENTROPY_STR, DEFAULT_NETWORK).unwrap();

let msg = "This is a message";

// Constant signature
let sig1 = "ff4cb99e0a9be8ec7dea1e51904cf22f71717c19fc3e7dcbc8346eb28bebffbb892c4c41e05c2383efda00f5acc9c7f3622d88a90630cd62d49db598c8ce10b9";
let verify_res = verify_schnorr(msg, &sig1, 0).unwrap();
assert_eq!(verify_res, true);

// Signature created here
let nonce = "0123450000000000006897528962743076432965432697856340567500000100";
let sig = sign_schnorr_with_nonce(msg, nonce, 0).unwrap();

let verify_res = verify_schnorr(msg, &sig, 0).unwrap();
assert_eq!(verify_res, true);

// Verify with different key index
let verify_res = verify_schnorr(msg, &sig, 1).unwrap();
assert_eq!(verify_res, false);

// Verify with a different message
let msg2 = "This is ANOTHER message";
let verify_res = verify_schnorr(msg2, &sig, 0).unwrap();
assert_eq!(verify_res, false);
}

fn create_dummy_pubkey(index: u8) -> PublicKey {
let sechex = format!(
"012345000000000000689752896274307643296543269785634056750000000{}",
Expand Down