diff --git a/src/lib.rs b/src/lib.rs index fedcbdd..addd863 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,11 +23,11 @@ use { }; mod error; -pub mod sign; -pub mod util; -pub mod verify; +mod sign; +mod util; +mod verify; -use util::*; +pub use {sign::*, util::*, verify::*}; type Result = std::result::Result; @@ -113,7 +113,7 @@ mod tests { #[test] fn simple_verify_and_falsify_taproot() { assert!( - verify::simple_encoded( + verify::verify_simple_encoded( TAPROOT_ADDRESS, "Hello World", "AUHd69PrJQEv+oKTfZ8l+WROBHuy9HKrbFCJu7U1iK2iiEy1vMU5EfMtjc+VSHM7aU0SDbak5IUZRVno2P5mjSafAQ==" @@ -121,7 +121,7 @@ mod tests { ); assert_eq!( - verify::simple_encoded( + verify::verify_simple_encoded( TAPROOT_ADDRESS, "Hello World -- This should fail", "AUHd69PrJQEv+oKTfZ8l+WROBHuy9HKrbFCJu7U1iK2iiEy1vMU5EfMtjc+VSHM7aU0SDbak5IUZRVno2P5mjSafAQ==" @@ -133,34 +133,34 @@ mod tests { #[test] fn simple_sign_taproot() { assert_eq!( - sign::simple_encoded(TAPROOT_ADDRESS, "Hello World", WIF_PRIVATE_KEY).unwrap(), + sign::sign_simple_encoded(TAPROOT_ADDRESS, "Hello World", WIF_PRIVATE_KEY).unwrap(), "AUHd69PrJQEv+oKTfZ8l+WROBHuy9HKrbFCJu7U1iK2iiEy1vMU5EfMtjc+VSHM7aU0SDbak5IUZRVno2P5mjSafAQ==" ); } #[test] fn roundtrip_taproot_simple() { - assert!(verify::simple_encoded( + assert!(verify::verify_simple_encoded( TAPROOT_ADDRESS, "Hello World", - &sign::simple_encoded(TAPROOT_ADDRESS, "Hello World", WIF_PRIVATE_KEY).unwrap() + &sign::sign_simple_encoded(TAPROOT_ADDRESS, "Hello World", WIF_PRIVATE_KEY).unwrap() ) .is_ok()); } #[test] fn roundtrip_taproot_full() { - assert!(verify::full_encoded( + assert!(verify::verify_full_encoded( TAPROOT_ADDRESS, "Hello World", - &sign::full_encoded(TAPROOT_ADDRESS, "Hello World", WIF_PRIVATE_KEY).unwrap() + &sign::sign_full_encoded(TAPROOT_ADDRESS, "Hello World", WIF_PRIVATE_KEY).unwrap() ) .is_ok()); } #[test] fn invalid_address() { - assert_eq!(verify::simple_encoded( + assert_eq!(verify::verify_simple_encoded( "3B5fQsEXEaV8v6U3ejYc8XaKXAkyQj2MjV", "", "AkcwRAIgM2gBAQqvZX15ZiysmKmQpDrG83avLIT492QBzLnQIxYCIBaTpOaD20qRlEylyxFSeEA2ba9YOixpX8z46TSDtS40ASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI=").unwrap_err().to_string(), @@ -171,7 +171,7 @@ mod tests { #[test] fn signature_decode_error() { assert_eq!( - verify::simple_encoded( + verify::verify_simple_encoded( TAPROOT_ADDRESS, "Hello World", "invalid signature not in base64 encoding" @@ -182,7 +182,7 @@ mod tests { ); assert_eq!( - verify::simple_encoded( + verify::verify_simple_encoded( TAPROOT_ADDRESS, "Hello World", "AkcwRAIgM2gBAQqvZX15ZiysmKmQpDrG83avLIT492QBzLnQIxYCIBaTpOaD20qRlEylyxFSeEA2ba9YOixpX8z46TSDtS40ASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViH" @@ -194,7 +194,7 @@ mod tests { #[test] fn simple_verify_and_falsify_p2wpkh() { assert!( - verify::simple_encoded( + verify::verify_simple_encoded( SEGWIT_ADDRESS, "Hello World", "AkcwRAIgZRfIY3p7/DoVTty6YZbWS71bc5Vct9p9Fia83eRmw2QCICK/ENGfwLtptFluMGs2KsqoNSk89pO7F29zJLUx9a/sASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI=" @@ -202,7 +202,7 @@ mod tests { ); assert!( - verify::simple_encoded( + verify::verify_simple_encoded( SEGWIT_ADDRESS, "Hello World - this should fail", "AkcwRAIgZRfIY3p7/DoVTty6YZbWS71bc5Vct9p9Fia83eRmw2QCICK/ENGfwLtptFluMGs2KsqoNSk89pO7F29zJLUx9a/sASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI=" @@ -210,7 +210,7 @@ mod tests { ); assert!( - verify::simple_encoded( + verify::verify_simple_encoded( SEGWIT_ADDRESS, "Hello World", "AkgwRQIhAOzyynlqt93lOKJr+wmmxIens//zPzl9tqIOua93wO6MAiBi5n5EyAcPScOjf1lAqIUIQtr3zKNeavYabHyR8eGhowEhAsfxIAMZZEKUPYWI4BruhAQjzFT8FSFSajuFwrDL1Yhy" @@ -218,7 +218,7 @@ mod tests { ); assert!( - verify::simple_encoded( + verify::verify_simple_encoded( SEGWIT_ADDRESS, "", "AkcwRAIgM2gBAQqvZX15ZiysmKmQpDrG83avLIT492QBzLnQIxYCIBaTpOaD20qRlEylyxFSeEA2ba9YOixpX8z46TSDtS40ASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI=" @@ -226,7 +226,7 @@ mod tests { ); assert!( - verify::simple_encoded( + verify::verify_simple_encoded( SEGWIT_ADDRESS, "fail", "AkcwRAIgM2gBAQqvZX15ZiysmKmQpDrG83avLIT492QBzLnQIxYCIBaTpOaD20qRlEylyxFSeEA2ba9YOixpX8z46TSDtS40ASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI=" @@ -234,7 +234,7 @@ mod tests { ); assert!( - verify::simple_encoded( + verify::verify_simple_encoded( SEGWIT_ADDRESS, "", "AkgwRQIhAPkJ1Q4oYS0htvyuSFHLxRQpFAY56b70UvE7Dxazen0ZAiAtZfFz1S6T6I23MWI2lK/pcNTWncuyL8UL+oMdydVgzAEhAsfxIAMZZEKUPYWI4BruhAQjzFT8FSFSajuFwrDL1Yhy" @@ -245,32 +245,32 @@ mod tests { #[test] fn simple_sign_p2wpkh() { assert_eq!( - sign::simple_encoded(SEGWIT_ADDRESS, "Hello World", WIF_PRIVATE_KEY).unwrap(), + sign::sign_simple_encoded(SEGWIT_ADDRESS, "Hello World", WIF_PRIVATE_KEY).unwrap(), "AkgwRQIhAOzyynlqt93lOKJr+wmmxIens//zPzl9tqIOua93wO6MAiBi5n5EyAcPScOjf1lAqIUIQtr3zKNeavYabHyR8eGhowEhAsfxIAMZZEKUPYWI4BruhAQjzFT8FSFSajuFwrDL1Yhy" ); assert_eq!( - sign::simple_encoded(SEGWIT_ADDRESS, "", WIF_PRIVATE_KEY).unwrap(), + sign::sign_simple_encoded(SEGWIT_ADDRESS, "", WIF_PRIVATE_KEY).unwrap(), "AkgwRQIhAPkJ1Q4oYS0htvyuSFHLxRQpFAY56b70UvE7Dxazen0ZAiAtZfFz1S6T6I23MWI2lK/pcNTWncuyL8UL+oMdydVgzAEhAsfxIAMZZEKUPYWI4BruhAQjzFT8FSFSajuFwrDL1Yhy" ); } #[test] fn roundtrip_p2wpkh_simple() { - assert!(verify::simple_encoded( + assert!(verify::verify_simple_encoded( SEGWIT_ADDRESS, "Hello World", - &sign::simple_encoded(SEGWIT_ADDRESS, "Hello World", WIF_PRIVATE_KEY).unwrap() + &sign::sign_simple_encoded(SEGWIT_ADDRESS, "Hello World", WIF_PRIVATE_KEY).unwrap() ) .is_ok()); } #[test] fn roundtrip_p2wpkh_full() { - assert!(verify::full_encoded( + assert!(verify::verify_full_encoded( SEGWIT_ADDRESS, "Hello World", - &sign::full_encoded(SEGWIT_ADDRESS, "Hello World", WIF_PRIVATE_KEY).unwrap() + &sign::sign_full_encoded(SEGWIT_ADDRESS, "Hello World", WIF_PRIVATE_KEY).unwrap() ) .is_ok()); } diff --git a/src/sign.rs b/src/sign.rs index 50dcc27..8c421d7 100644 --- a/src/sign.rs +++ b/src/sign.rs @@ -1,14 +1,14 @@ use super::*; /// Signs the BIP-322 simple from spec-compliant string encodings. -pub fn simple_encoded(address: &str, message: &str, wif_private_key: &str) -> Result { +pub fn sign_simple_encoded(address: &str, message: &str, wif_private_key: &str) -> Result { let address = Address::from_str(address) .context(error::AddressParse { address })? .assume_checked(); let private_key = PrivateKey::from_wif(wif_private_key).context(error::PrivateKeyParse)?; - let witness = simple(&address, message.as_bytes(), private_key)?; + let witness = sign_simple(&address, message.as_bytes(), private_key)?; let mut buffer = Vec::new(); @@ -20,14 +20,14 @@ pub fn simple_encoded(address: &str, message: &str, wif_private_key: &str) -> Re } /// Signs the BIP-322 full from spec-compliant string encodings. -pub fn full_encoded(address: &str, message: &str, wif_private_key: &str) -> Result { +pub fn sign_full_encoded(address: &str, message: &str, wif_private_key: &str) -> Result { let address = Address::from_str(address) .context(error::AddressParse { address })? .assume_checked(); let private_key = PrivateKey::from_wif(wif_private_key).context(error::PrivateKeyParse)?; - let tx = full(&address, message.as_bytes(), private_key)?; + let tx = sign_full(&address, message.as_bytes(), private_key)?; let mut buffer = Vec::new(); @@ -38,16 +38,20 @@ pub fn full_encoded(address: &str, message: &str, wif_private_key: &str) -> Resu } /// Signs in the BIP-322 simple format from proper Rust types and returns the witness. -pub fn simple(address: &Address, message: &[u8], private_key: PrivateKey) -> Result { +pub fn sign_simple(address: &Address, message: &[u8], private_key: PrivateKey) -> Result { Ok( - full(address, message, private_key)?.input[0] + sign_full(address, message, private_key)?.input[0] .witness .clone(), ) } /// Signs in the BIP-322 full format from proper Rust types and returns the full transaction. -pub fn full(address: &Address, message: &[u8], private_key: PrivateKey) -> Result { +pub fn sign_full( + address: &Address, + message: &[u8], + private_key: PrivateKey, +) -> Result { let to_spend = create_to_spend(address, message)?; let mut to_sign = create_to_sign(&to_spend, None)?; diff --git a/src/util.rs b/src/util.rs index 1ba284d..ee38356 100644 --- a/src/util.rs +++ b/src/util.rs @@ -2,6 +2,7 @@ use super::*; const TAG: &str = "BIP0322-signed-message"; +/// Create the tagged message hash. pub fn message_hash(message: &[u8]) -> Vec { let mut tag_hash = sha256::Hash::hash(TAG.as_bytes()).to_byte_array().to_vec(); tag_hash.extend(tag_hash.clone()); @@ -12,6 +13,7 @@ pub fn message_hash(message: &[u8]) -> Vec { .to_vec() } +/// Create the `to_spend` transaction. pub fn create_to_spend(address: &Address, message: &[u8]) -> Result { Ok(Transaction { version: Version(0), @@ -37,6 +39,7 @@ pub fn create_to_spend(address: &Address, message: &[u8]) -> Result }) } +/// Create the `to_sign` transaction. pub fn create_to_sign(to_spend: &Transaction, witness: Option) -> Result { let inputs = vec![TxIn { previous_output: OutPoint { diff --git a/src/verify.rs b/src/verify.rs index ef75684..6abb52d 100644 --- a/src/verify.rs +++ b/src/verify.rs @@ -1,7 +1,7 @@ use super::*; /// Verifies the BIP-322 simple from spec-compliant string encodings. -pub fn simple_encoded(address: &str, message: &str, signature: &str) -> Result<()> { +pub fn verify_simple_encoded(address: &str, message: &str, signature: &str) -> Result<()> { let address = Address::from_str(address) .context(error::AddressParse { address })? .assume_checked(); @@ -15,11 +15,11 @@ pub fn simple_encoded(address: &str, message: &str, signature: &str) -> Result<( let witness = Witness::consensus_decode_from_finite_reader(&mut cursor).context(error::WitnessMalformed)?; - simple(&address, message.as_bytes(), witness) + verify_simple(&address, message.as_bytes(), witness) } /// Verifies the BIP-322 full from spec-compliant string encodings. -pub fn full_encoded(address: &str, message: &str, to_sign: &str) -> Result<()> { +pub fn verify_full_encoded(address: &str, message: &str, to_sign: &str) -> Result<()> { let address = Address::from_str(address) .context(error::AddressParse { address })? .assume_checked(); @@ -36,12 +36,12 @@ pub fn full_encoded(address: &str, message: &str, to_sign: &str) -> Result<()> { }, )?; - full(&address, message.as_bytes(), to_sign) + verify_full(&address, message.as_bytes(), to_sign) } /// Verifies the BIP-322 simple from proper Rust types. -pub fn simple(address: &Address, message: &[u8], signature: Witness) -> Result<()> { - full( +pub fn verify_simple(address: &Address, message: &[u8], signature: Witness) -> Result<()> { + verify_full( address, message, create_to_sign(&create_to_spend(address, message)?, Some(signature))? @@ -51,17 +51,17 @@ pub fn simple(address: &Address, message: &[u8], signature: Witness) -> Result<( } /// Verifies the BIP-322 full from proper Rust types. -pub fn full(address: &Address, message: &[u8], to_sign: Transaction) -> Result<()> { +pub fn verify_full(address: &Address, message: &[u8], to_sign: Transaction) -> Result<()> { match address.payload() { Payload::WitnessProgram(wp) if wp.version().to_num() == 0 && wp.program().len() == 20 => { let pub_key = PublicKey::from_slice(&to_sign.input[0].witness[1]).map_err(|_| Error::InvalidPublicKey)?; - full_p2wpkh(address, message, to_sign, pub_key) + verify_full_p2wpkh(address, message, to_sign, pub_key) } Payload::WitnessProgram(wp) if wp.version().to_num() == 1 && wp.program().len() == 32 => { let pub_key = XOnlyPublicKey::from_slice(wp.program().as_bytes()).map_err(|_| Error::InvalidPublicKey)?; - full_p2tr(address, message, to_sign, pub_key) + verify_full_p2tr(address, message, to_sign, pub_key) } _ => Err(Error::UnsupportedAddress { address: address.to_string(), @@ -69,7 +69,7 @@ pub fn full(address: &Address, message: &[u8], to_sign: Transaction) -> Result<( } } -fn full_p2wpkh( +fn verify_full_p2wpkh( address: &Address, message: &[u8], to_sign: Transaction, @@ -147,7 +147,7 @@ fn full_p2wpkh( Ok(()) } -fn full_p2tr( +fn verify_full_p2tr( address: &Address, message: &[u8], to_sign: Transaction,