From b01276c491c9f40417f51af4d48255d7db5a5a77 Mon Sep 17 00:00:00 2001 From: Supreme2580 Date: Tue, 22 Oct 2024 19:37:53 +0100 Subject: [PATCH 1/3] taproot::new --- packages/engine/src/signature/constants.cairo | 5 ++++ packages/engine/src/signature/signature.cairo | 28 +++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/packages/engine/src/signature/constants.cairo b/packages/engine/src/signature/constants.cairo index a543cfab..026648ee 100644 --- a/packages/engine/src/signature/constants.cairo +++ b/packages/engine/src/signature/constants.cairo @@ -44,3 +44,8 @@ pub const WITNESS_V0_PUB_KEY_HASH_LEN: usize = 22; pub const MAX_U128: u128 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; pub const MAX_U32: u32 = 0xFFFFFFFF; + +pub const SCHNORR_SIGNATURE_LEN: usize = 64; + +pub const PUB_KEY_BYTES_LEN: usize = 32; +pub const PUB_KEY_BYTES_LEN_COMPRESSED: usize = 33; diff --git a/packages/engine/src/signature/signature.cairo b/packages/engine/src/signature/signature.cairo index 30c08e4f..59ab435a 100644 --- a/packages/engine/src/signature/signature.cairo +++ b/packages/engine/src/signature/signature.cairo @@ -603,8 +603,32 @@ pub impl TaprootSigVerifierImpl< fn new( sig_bytes: @ByteArray, pk_bytes: @ByteArray, annex: @ByteArray ) -> Result { - // TODO - return Result::Err('TaprootSig not implemented'); + if sig_bytes.len() != 64 && sig_bytes.len() != 65 { + return Result::Err('Invalid Schnorr signature'); + } + + if pk_bytes.len() != 32 { + return Result::Err('Invalid public key length'); + } + + let hash_type = if sig_bytes.len() == 65 { + sig_bytes[64].into() + } else { + constants::SIG_HASH_DEFAULT + }; + + let pub_key = parse_schnorr_pub_key(pk_bytes); + let sig = 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 + }; + + Result::Ok( + TaprootSigVerifier { + pub_key, sig, sig_bytes: sig_bytes, pk_bytes: pk_bytes, hash_type, annex, + } + ) } fn new_base( From 5f18b06432687796a5bfb2590f13a7762e9c6f44 Mon Sep 17 00:00:00 2001 From: Brandon Roberts Date: Mon, 28 Oct 2024 00:44:02 -0500 Subject: [PATCH 2/3] Merge stuff in --- packages/engine/src/opcodes/crypto.cairo | 2 +- packages/engine/src/signature/constants.cairo | 5 -- packages/engine/src/signature/signature.cairo | 73 ++++++++++++------- 3 files changed, 48 insertions(+), 32 deletions(-) diff --git a/packages/engine/src/opcodes/crypto.cairo b/packages/engine/src/opcodes/crypto.cairo index f804e280..646d3cf6 100644 --- a/packages/engine/src/opcodes/crypto.cairo +++ b/packages/engine/src/opcodes/crypto.cairo @@ -115,7 +115,7 @@ pub fn opcode_checksig< } // TODO: Errors or false? - let mut verifier = TaprootSigVerifierTrait::::new_base(@full_sig_bytes, @pk_bytes)?; + let mut verifier = TaprootSigVerifierTrait::::new_base(@full_sig_bytes, @pk_bytes, ref engine)?; is_valid = TaprootSigVerifierTrait::::verify(ref verifier); } diff --git a/packages/engine/src/signature/constants.cairo b/packages/engine/src/signature/constants.cairo index 026648ee..a543cfab 100644 --- a/packages/engine/src/signature/constants.cairo +++ b/packages/engine/src/signature/constants.cairo @@ -44,8 +44,3 @@ pub const WITNESS_V0_PUB_KEY_HASH_LEN: usize = 22; pub const MAX_U128: u128 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; pub const MAX_U32: u32 = 0xFFFFFFFF; - -pub const SCHNORR_SIGNATURE_LEN: usize = 64; - -pub const PUB_KEY_BYTES_LEN: usize = 32; -pub const PUB_KEY_BYTES_LEN_COMPRESSED: usize = 33; diff --git a/packages/engine/src/signature/signature.cairo b/packages/engine/src/signature/signature.cairo index 59ab435a..77322836 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,23 @@ 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 +595,17 @@ 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,29 +619,22 @@ 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 { - if sig_bytes.len() != 64 && sig_bytes.len() != 65 { - return Result::Err('Invalid Schnorr signature'); - } - - if pk_bytes.len() != 32 { - return Result::Err('Invalid public key length'); - } - - let hash_type = if sig_bytes.len() == 65 { - sig_bytes[64].into() - } else { - constants::SIG_HASH_DEFAULT - }; - - let pub_key = parse_schnorr_pub_key(pk_bytes); - let sig = 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 - }; + let pub_key = parse_schnorr_pub_key(pk_bytes)?; + let (sig, hash_type) = schnorr_parse_signature(sig_bytes)?; Result::Ok( TaprootSigVerifier { @@ -632,10 +644,19 @@ pub impl TaprootSigVerifierImpl< } 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 { From 2cc949d86bdbce4aa7e9ced302e6ba36aec2aea6 Mon Sep 17 00:00:00 2001 From: Brandon Roberts Date: Mon, 28 Oct 2024 00:44:16 -0500 Subject: [PATCH 3/3] Scarb fmt --- packages/engine/src/opcodes/crypto.cairo | 4 +++- packages/engine/src/signature/signature.cairo | 21 ++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/engine/src/opcodes/crypto.cairo b/packages/engine/src/opcodes/crypto.cairo index 646d3cf6..e7bfc924 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, ref engine)?; + 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 77322836..1201de7a 100644 --- a/packages/engine/src/signature/signature.cairo +++ b/packages/engine/src/signature/signature.cairo @@ -467,11 +467,16 @@ pub fn schnorr_parse_signature(sig_bytes: @ByteArray) -> Result<(Signature, u32) } 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)) + 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. @@ -599,7 +604,9 @@ pub trait TaprootSigVerifierTrait { fn new( sig_bytes: @ByteArray, pk_bytes: @ByteArray, annex: @ByteArray ) -> Result; - fn new_base(sig_bytes: @ByteArray, pk_bytes: @ByteArray, ref engine: Engine) -> 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; } @@ -622,7 +629,7 @@ pub impl TaprootSigVerifierImpl< fn empty() -> TaprootSigVerifier { TaprootSigVerifier { pub_key: Secp256Trait::::get_generator_point(), - sig: Signature{ r: 0, s: 0, y_parity: false }, + sig: Signature { r: 0, s: 0, y_parity: false }, sig_bytes: @"", pk_bytes: @"", hash_type: 0,