Skip to content

Commit

Permalink
Amend
Browse files Browse the repository at this point in the history
  • Loading branch information
raphjaph committed Aug 10, 2024
1 parent a675b45 commit efc7ed1
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 41 deletions.
37 changes: 31 additions & 6 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,51 @@
use super::*;

#[derive(Debug, Snafu, PartialEq)]
#[derive(Debug, Snafu)]
#[snafu(context(suffix(false)), visibility(pub))]
pub enum Error {
#[snafu(display("Failed to parse address `{address}`"))]
AddressParse {
source: bitcoin::address::ParseError,
address: String,
},
#[snafu(display("Invalid address"))]
InvalidAddress,
#[snafu(display("Unsuported address `{address}`, only P2TR allowed"))]
UnsupportedAddress { address: String },
#[snafu(display("Invalid"))]
Invalid,
#[snafu(display("Decode error for signature `{signature}`"))]
SignatureDecode {
source: base64::DecodeError,
signature: String,
},
#[snafu(display("Malformed signature"))]
MalformedSignature,
#[snafu(display("Base64 decode error for transaction `{transaction}`"))]
TransactionDecode {
source: base64::DecodeError,
transaction: String,
},
#[snafu(display("Consensu decode error for transaction `{transaction}`"))]
TransactionConsensusDecode {
source: bitcoin::consensus::encode::Error,
transaction: String,
},
#[snafu(display("Witness signature"))]
MalformedWitness {
source: bitcoin::consensus::encode::Error,
},
#[snafu(display("Signature of wrong length `{length}`"))]
SignatureLength {
length: usize,
encoded_signature: Vec<u8>,
},
#[snafu(display("Invalid signature because: `{}`", source.to_string()))]
InvalidSignature {
source: bitcoin::secp256k1::Error,
},
#[snafu(display("Invalid sighash"))]
InvalidSigHash,
InvalidSigHash {
source: bitcoin::sighash::InvalidSighashTypeError,
},
#[snafu(display("Unsupported sighash type `{sighash_type}`"))]
UnsupportedSigHash { sighash_type: String },
#[snafu(display("Not key path spend"))]
NotKeyPathSpend,
}
26 changes: 11 additions & 15 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ pub(crate) fn create_to_sign(to_spend: &Transaction, witness: Option<Witness>) -

#[cfg(test)]
mod tests {
use {super::*, error::Error, pretty_assertions::assert_eq};
use {super::*, pretty_assertions::assert_eq};

/// From https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki#test-vectors
/// and https://github.com/ACken2/bip322-js/blob/main/test/Verifier.test.ts
Expand Down Expand Up @@ -218,8 +218,8 @@ mod tests {
TAPROOT_ADDRESS,
"Hello World -- This should fail",
"AUHd69PrJQEv+oKTfZ8l+WROBHuy9HKrbFCJu7U1iK2iiEy1vMU5EfMtjc+VSHM7aU0SDbak5IUZRVno2P5mjSafAQ=="
),
Err(Error::Invalid)
).unwrap_err().to_string(),
"Invalid"
);
}

Expand Down Expand Up @@ -276,8 +276,8 @@ mod tests {
assert_eq!(simple_verify(
"3B5fQsEXEaV8v6U3ejYc8XaKXAkyQj2MjV",
"",
"AkcwRAIgM2gBAQqvZX15ZiysmKmQpDrG83avLIT492QBzLnQIxYCIBaTpOaD20qRlEylyxFSeEA2ba9YOixpX8z46TSDtS40ASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI="),
Err(Error::InvalidAddress)
"AkcwRAIgM2gBAQqvZX15ZiysmKmQpDrG83avLIT492QBzLnQIxYCIBaTpOaD20qRlEylyxFSeEA2ba9YOixpX8z46TSDtS40ASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViHI=").unwrap_err().to_string(),
"Unsuported address `3B5fQsEXEaV8v6U3ejYc8XaKXAkyQj2MjV`, only P2TR allowed"
)
}

Expand All @@ -288,23 +288,19 @@ mod tests {
TAPROOT_ADDRESS,
"Hello World",
"invalid signature not in base64 encoding"
),
Err(Error::SignatureDecode {
source: base64::DecodeError::InvalidByte(7, 32,),
signature: "invalid signature not in base64 encoding".to_string(),
})
)
.unwrap_err()
.to_string(),
"Decode error for signature `invalid signature not in base64 encoding`"
);

assert_eq!(
simple_verify(
TAPROOT_ADDRESS,
"Hello World",
"AkcwRAIgM2gBAQqvZX15ZiysmKmQpDrG83avLIT492QBzLnQIxYCIBaTpOaD20qRlEylyxFSeEA2ba9YOixpX8z46TSDtS40ASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViH"
),
Err(Error::SignatureDecode {
source: base64::DecodeError::InvalidPadding,
signature: "AkcwRAIgM2gBAQqvZX15ZiysmKmQpDrG83avLIT492QBzLnQIxYCIBaTpOaD20qRlEylyxFSeEA2ba9YOixpX8z46TSDtS40ASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViH".to_string(),
})
).unwrap_err().to_string(),
"Decode error for signature `AkcwRAIgM2gBAQqvZX15ZiysmKmQpDrG83avLIT492QBzLnQIxYCIBaTpOaD20qRlEylyxFSeEA2ba9YOixpX8z46TSDtS40ASECx/EgAxlkQpQ9hYjgGu6EBCPMVPwVIVJqO4XCsMvViH`"
)
}
}
53 changes: 33 additions & 20 deletions src/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@ pub fn simple_verify(address: &str, message: &str, signature: &str) -> Result<()
.context(error::SignatureDecode { signature })?,
);

let witness = match Witness::consensus_decode_from_finite_reader(&mut cursor) {
Ok(witness) => witness,
Err(_) => return Err(Error::MalformedSignature),
};
let witness =
Witness::consensus_decode_from_finite_reader(&mut cursor).context(error::MalformedWitness)?;

simple_verify_inner(&address, message.as_bytes(), witness)
}
Expand All @@ -41,14 +39,17 @@ pub fn full_verify(address: &str, message: &str, to_sign: &str) -> Result<()> {
.context(error::AddressParse { address })?
.assume_checked();

let mut cursor = Cursor::new(
general_purpose::STANDARD
.decode(to_sign)
.map_err(|_| Error::MalformedSignature)?,
);
let mut cursor = Cursor::new(general_purpose::STANDARD.decode(to_sign).context(
error::TransactionDecode {
transaction: to_sign,
},
)?);

let to_sign = Transaction::consensus_decode_from_finite_reader(&mut cursor)
.map_err(|_| Error::MalformedSignature)?;
let to_sign = Transaction::consensus_decode_from_finite_reader(&mut cursor).context(
error::TransactionConsensusDecode {
transaction: to_sign,
},
)?;

full_verify_inner(&address, message.as_bytes(), to_sign)
}
Expand All @@ -59,13 +60,17 @@ pub fn full_verify_inner(address: &Address, message: &[u8], to_sign: Transaction
.address_type()
.is_some_and(|addr| addr != AddressType::P2tr)
{
return Err(Error::InvalidAddress);
return Err(Error::UnsupportedAddress {
address: address.to_string(),
});
}

let pub_key =
if let bitcoin::address::Payload::WitnessProgram(witness_program) = address.payload() {
if witness_program.version().to_num() != 1 {
return Err(Error::InvalidAddress);
return Err(Error::UnsupportedAddress {
address: address.to_string(),
});
}

if witness_program.program().len() != 32 {
Expand All @@ -75,7 +80,9 @@ pub fn full_verify_inner(address: &Address, message: &[u8], to_sign: Transaction
XOnlyPublicKey::from_slice(witness_program.program().as_bytes())
.expect("should extract an xonly public key")
} else {
return Err(Error::InvalidAddress);
return Err(Error::UnsupportedAddress {
address: address.to_string(),
});
};

let to_spend = create_to_spend(address, message);
Expand Down Expand Up @@ -104,19 +111,25 @@ pub fn full_verify_inner(address: &Address, message: &[u8], to_sign: Transaction
let (signature, sighash_type) = match encoded_signature.len() {
65 => (
Signature::from_slice(&encoded_signature.as_slice()[..64])
.map_err(|_| Error::MalformedSignature)?,
TapSighashType::from_consensus_u8(encoded_signature[64])
.map_err(|_| Error::InvalidSigHash)?,
.context(error::InvalidSignature)?,
TapSighashType::from_consensus_u8(encoded_signature[64]).context(error::InvalidSigHash)?,
),
64 => (
Signature::from_slice(encoded_signature.as_slice()).map_err(|_| Error::MalformedSignature)?,
Signature::from_slice(encoded_signature.as_slice()).context(error::InvalidSignature)?,
TapSighashType::Default,
),
_ => return Err(Error::MalformedSignature),
_ => {
return Err(Error::SignatureLength {
length: encoded_signature.len(),
encoded_signature,
})
}
};

if !(sighash_type == TapSighashType::All || sighash_type == TapSighashType::Default) {
return Err(Error::InvalidSigHash);
return Err(Error::UnsupportedSigHash {
sighash_type: sighash_type.to_string(),
});
}

let mut sighash_cache = SighashCache::new(to_sign.unsigned_tx);
Expand Down

0 comments on commit efc7ed1

Please sign in to comment.