diff --git a/packages/engine/src/opcodes/crypto.cairo b/packages/engine/src/opcodes/crypto.cairo index f804e28..e7bfc92 100644 --- a/packages/engine/src/opcodes/crypto.cairo +++ b/packages/engine/src/opcodes/crypto.cairo @@ -115,7 +115,9 @@ pub fn opcode_checksig< } // TODO: Errors or false? - let mut verifier = TaprootSigVerifierTrait::::new_base(@full_sig_bytes, @pk_bytes)?; + let mut verifier = TaprootSigVerifierTrait::< + T + >::new_base(@full_sig_bytes, @pk_bytes, ref engine)?; is_valid = TaprootSigVerifierTrait::::verify(ref verifier); } diff --git a/packages/engine/src/signature/signature.cairo b/packages/engine/src/signature/signature.cairo index 30c08e4..1201de7 100644 --- a/packages/engine/src/signature/signature.cairo +++ b/packages/engine/src/signature/signature.cairo @@ -390,8 +390,7 @@ pub fn parse_pub_key(pk_bytes: @ByteArray) -> Result { pub fn parse_schnorr_pub_key(pk_bytes: @ByteArray) -> Result { if pk_bytes.len() == 0 || pk_bytes.len() != 32 { - // TODO - panic!("invalid schnorr pubkey length"); + return Result::Err('Invalid schnorr pubkey length'); } let mut key_compressed: ByteArray = "\02"; @@ -458,6 +457,28 @@ pub fn parse_signature(sig_bytes: @ByteArray) -> Result { return Result::Ok(Signature { r: r_sig, s: s_sig, y_parity: false, }); } +pub fn schnorr_parse_signature(sig_bytes: @ByteArray) -> Result<(Signature, u32), felt252> { + let sig_bytes_len = sig_bytes.len(); + let mut hash_type: u32 = 0; + if sig_bytes_len == SCHNORR_SIGNATURE_LEN { + hash_type = constants::SIG_HASH_DEFAULT; + } else if sig_bytes_len == SCHNORR_SIGNATURE_LEN + 1 && sig_bytes[64] != 0 { + hash_type = sig_bytes[64].into(); + } else { + return Result::Err('Invalid taproot signature len'); + } + Result::Ok( + ( + Signature { + r: u256_from_byte_array_with_offset(sig_bytes, 0, 32), + s: u256_from_byte_array_with_offset(sig_bytes, 32, 32), + y_parity: false, // Schnorr signatures don't use y_parity + }, + hash_type + ) + ) +} + // Parses the public key and signature byte arrays based on consensus rules. // Returning a tuple containing the parsed public key, signature, and hash type. pub fn parse_base_sig_and_pk< @@ -579,14 +600,19 @@ pub struct TaprootSigVerifier { } pub trait TaprootSigVerifierTrait { + fn empty() -> TaprootSigVerifier; fn new( sig_bytes: @ByteArray, pk_bytes: @ByteArray, annex: @ByteArray ) -> Result; - fn new_base(sig_bytes: @ByteArray, pk_bytes: @ByteArray) -> Result; + fn new_base( + sig_bytes: @ByteArray, pk_bytes: @ByteArray, ref engine: Engine + ) -> Result; fn verify(ref self: TaprootSigVerifier) -> bool; fn verify_base(ref self: TaprootSigVerifier) -> bool; } +pub const SCHNORR_SIGNATURE_LEN: usize = 64; + pub impl TaprootSigVerifierImpl< T, +Drop, @@ -600,18 +626,44 @@ pub impl TaprootSigVerifierImpl< T, I, O, IEngineTransactionInputTrait, IEngineTransactionOutputTrait > > of TaprootSigVerifierTrait { + fn empty() -> TaprootSigVerifier { + TaprootSigVerifier { + pub_key: Secp256Trait::::get_generator_point(), + sig: Signature { r: 0, s: 0, y_parity: false }, + sig_bytes: @"", + pk_bytes: @"", + hash_type: 0, + annex: @"" + } + } + fn new( sig_bytes: @ByteArray, pk_bytes: @ByteArray, annex: @ByteArray ) -> Result { - // TODO - return Result::Err('TaprootSig not implemented'); + let pub_key = parse_schnorr_pub_key(pk_bytes)?; + let (sig, hash_type) = schnorr_parse_signature(sig_bytes)?; + + Result::Ok( + TaprootSigVerifier { + pub_key, sig, sig_bytes: sig_bytes, pk_bytes: pk_bytes, hash_type, annex, + } + ) } fn new_base( - sig_bytes: @ByteArray, pk_bytes: @ByteArray + sig_bytes: @ByteArray, pk_bytes: @ByteArray, ref engine: Engine ) -> Result { - // TODO - return Result::Err('TaprootSig not implemented'); + let pk_bytes_len = pk_bytes.len(); + if pk_bytes_len == 0 { + return Result::Err('Taproot empty public key'); + } else if pk_bytes_len == 32 { + return Self::new(sig_bytes, pk_bytes, engine.taproot_context.annex); + } else { + if engine.has_flag(ScriptFlags::ScriptVerifyDiscourageUpgradeablePubkeyType) { + return Result::Err('Unknown pub key type'); + } + return Result::Ok(Self::empty()); + } } fn verify(ref self: TaprootSigVerifier) -> bool {