@ -11,6 +11,7 @@
# include <script/signingprovider.h>
# include <script/standard.h>
# include <uint256.h>
# include <util/vector.h>
typedef std : : vector < unsigned char > valtype ;
@ -30,6 +31,8 @@ MutableTransactionSignatureCreator::MutableTransactionSignatureCreator(const CMu
bool MutableTransactionSignatureCreator : : CreateSig ( const SigningProvider & provider , std : : vector < unsigned char > & vchSig , const CKeyID & address , const CScript & scriptCode , SigVersion sigversion ) const
{
assert ( sigversion = = SigVersion : : BASE | | sigversion = = SigVersion : : WITNESS_V0 ) ;
CKey key ;
if ( ! provider . GetKey ( address , key ) )
return false ;
@ -48,6 +51,51 @@ bool MutableTransactionSignatureCreator::CreateSig(const SigningProvider& provid
return true ;
}
bool MutableTransactionSignatureCreator : : CreateSchnorrSig ( const SigningProvider & provider , std : : vector < unsigned char > & sig , const XOnlyPubKey & pubkey , const uint256 * leaf_hash , const uint256 * merkle_root , SigVersion sigversion ) const
{
assert ( sigversion = = SigVersion : : TAPROOT | | sigversion = = SigVersion : : TAPSCRIPT ) ;
CKey key ;
{
// For now, use the old full pubkey-based key derivation logic. As it indexed by
// Hash160(full pubkey), we need to try both a version prefixed with 0x02, and one
// with 0x03.
unsigned char b [ 33 ] = { 0x02 } ;
std : : copy ( pubkey . begin ( ) , pubkey . end ( ) , b + 1 ) ;
CPubKey fullpubkey ;
fullpubkey . Set ( b , b + 33 ) ;
CKeyID keyid = fullpubkey . GetID ( ) ;
if ( ! provider . GetKey ( keyid , key ) ) {
b [ 0 ] = 0x03 ;
fullpubkey . Set ( b , b + 33 ) ;
CKeyID keyid = fullpubkey . GetID ( ) ;
if ( ! provider . GetKey ( keyid , key ) ) return false ;
}
}
// BIP341/BIP342 signing needs lots of precomputed transaction data. While some
// (non-SIGHASH_DEFAULT) sighash modes exist that can work with just some subset
// of data present, for now, only support signing when everything is provided.
if ( ! m_txdata | | ! m_txdata - > m_bip341_taproot_ready | | ! m_txdata - > m_spent_outputs_ready ) return false ;
ScriptExecutionData execdata ;
execdata . m_annex_init = true ;
execdata . m_annex_present = false ; // Only support annex-less signing for now.
if ( sigversion = = SigVersion : : TAPSCRIPT ) {
execdata . m_codeseparator_pos_init = true ;
execdata . m_codeseparator_pos = 0xFFFFFFFF ; // Only support non-OP_CODESEPARATOR BIP342 signing for now.
if ( ! leaf_hash ) return false ; // BIP342 signing needs leaf hash.
execdata . m_tapleaf_hash_init = true ;
execdata . m_tapleaf_hash = * leaf_hash ;
}
uint256 hash ;
if ( ! SignatureHashSchnorr ( hash , execdata , * txTo , nIn , nHashType , sigversion , * m_txdata , MissingDataBehavior : : FAIL ) ) return false ;
sig . resize ( 64 ) ;
if ( ! key . SignSchnorr ( hash , sig , merkle_root , nullptr ) ) return false ;
if ( nHashType ) sig . push_back ( nHashType ) ;
return true ;
}
static bool GetCScript ( const SigningProvider & provider , const SignatureData & sigdata , const CScriptID & scriptid , CScript & script )
{
if ( provider . GetCScript ( scriptid , script ) ) {
@ -104,6 +152,86 @@ static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdat
return false ;
}
static bool CreateTaprootScriptSig ( const BaseSignatureCreator & creator , SignatureData & sigdata , const SigningProvider & provider , std : : vector < unsigned char > & sig_out , const XOnlyPubKey & pubkey , const uint256 & leaf_hash , SigVersion sigversion )
{
auto lookup_key = std : : make_pair ( pubkey , leaf_hash ) ;
auto it = sigdata . taproot_script_sigs . find ( lookup_key ) ;
if ( it ! = sigdata . taproot_script_sigs . end ( ) ) {
sig_out = it - > second ;
}
if ( creator . CreateSchnorrSig ( provider , sig_out , pubkey , & leaf_hash , nullptr , sigversion ) ) {
sigdata . taproot_script_sigs [ lookup_key ] = sig_out ;
return true ;
}
return false ;
}
static bool SignTaprootScript ( const SigningProvider & provider , const BaseSignatureCreator & creator , SignatureData & sigdata , int leaf_version , const CScript & script , std : : vector < valtype > & result )
{
// Only BIP342 tapscript signing is supported for now.
if ( leaf_version ! = TAPROOT_LEAF_TAPSCRIPT ) return false ;
SigVersion sigversion = SigVersion : : TAPSCRIPT ;
uint256 leaf_hash = ( CHashWriter ( HASHER_TAPLEAF ) < < uint8_t ( leaf_version ) < < script ) . GetSHA256 ( ) ;
// <xonly pubkey> OP_CHECKSIG
if ( script . size ( ) = = 34 & & script [ 33 ] = = OP_CHECKSIG & & script [ 0 ] = = 0x20 ) {
XOnlyPubKey pubkey ( MakeSpan ( script ) . subspan ( 1 , 32 ) ) ;
std : : vector < unsigned char > sig ;
if ( CreateTaprootScriptSig ( creator , sigdata , provider , sig , pubkey , leaf_hash , sigversion ) ) {
result = Vector ( std : : move ( sig ) ) ;
return true ;
}
}
return false ;
}
static bool SignTaproot ( const SigningProvider & provider , const BaseSignatureCreator & creator , const WitnessV1Taproot & output , SignatureData & sigdata , std : : vector < valtype > & result )
{
TaprootSpendData spenddata ;
// Gather information about this output.
if ( provider . GetTaprootSpendData ( output , spenddata ) ) {
sigdata . tr_spenddata . Merge ( spenddata ) ;
}
// Try key path spending.
{
std : : vector < unsigned char > sig ;
if ( sigdata . taproot_key_path_sig . size ( ) = = 0 ) {
if ( creator . CreateSchnorrSig ( provider , sig , spenddata . internal_key , nullptr , & spenddata . merkle_root , SigVersion : : TAPROOT ) ) {
sigdata . taproot_key_path_sig = sig ;
}
}
if ( sigdata . taproot_key_path_sig . size ( ) ) {
result = Vector ( sigdata . taproot_key_path_sig ) ;
return true ;
}
}
// Try script path spending.
std : : vector < std : : vector < unsigned char > > smallest_result_stack ;
for ( const auto & [ key , control_blocks ] : sigdata . tr_spenddata . scripts ) {
const auto & [ script , leaf_ver ] = key ;
std : : vector < std : : vector < unsigned char > > result_stack ;
if ( SignTaprootScript ( provider , creator , sigdata , leaf_ver , script , result_stack ) ) {
result_stack . emplace_back ( std : : begin ( script ) , std : : end ( script ) ) ; // Push the script
result_stack . push_back ( * control_blocks . begin ( ) ) ; // Push the smallest control block
if ( smallest_result_stack . size ( ) = = 0 | |
GetSerializeSize ( result_stack , PROTOCOL_VERSION ) < GetSerializeSize ( smallest_result_stack , PROTOCOL_VERSION ) ) {
smallest_result_stack = std : : move ( result_stack ) ;
}
}
}
if ( smallest_result_stack . size ( ) ! = 0 ) {
result = std : : move ( smallest_result_stack ) ;
return true ;
}
return false ;
}
/**
* Sign scriptPubKey using signature made with creator .
* Signatures are returned in scriptSigRet ( or returns false if scriptPubKey can ' t be signed ) ,
@ -125,7 +253,6 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
case TxoutType : : NONSTANDARD :
case TxoutType : : NULL_DATA :
case TxoutType : : WITNESS_UNKNOWN :
case TxoutType : : WITNESS_V1_TAPROOT :
return false ;
case TxoutType : : PUBKEY :
if ( ! CreateSig ( creator , sigdata , provider , sig , CPubKey ( vSolutions [ 0 ] ) , scriptPubKey , sigversion ) ) return false ;
@ -187,6 +314,9 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
// Could not find witnessScript, add to missing
sigdata . missing_witness_script = uint256 ( vSolutions [ 0 ] ) ;
return false ;
case TxoutType : : WITNESS_V1_TAPROOT :
return SignTaproot ( provider , creator , WitnessV1Taproot ( XOnlyPubKey { vSolutions [ 0 ] } ) , sigdata , ret ) ;
} // no default case, so the compiler can warn about missing cases
assert ( false ) ;
}
@ -249,6 +379,12 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
sigdata . scriptWitness . stack = result ;
sigdata . witness = true ;
result . clear ( ) ;
} else if ( whichType = = TxoutType : : WITNESS_V1_TAPROOT & & ! P2SH ) {
sigdata . witness = true ;
if ( solved ) {
sigdata . scriptWitness . stack = std : : move ( result ) ;
}
result . clear ( ) ;
} else if ( solved & & whichType = = TxoutType : : WITNESS_UNKNOWN ) {
sigdata . witness = true ;
}
@ -414,6 +550,7 @@ class DummySignatureChecker final : public BaseSignatureChecker
public :
DummySignatureChecker ( ) { }
bool CheckECDSASignature ( const std : : vector < unsigned char > & scriptSig , const std : : vector < unsigned char > & vchPubKey , const CScript & scriptCode , SigVersion sigversion ) const override { return true ; }
bool CheckSchnorrSignature ( Span < const unsigned char > sig , Span < const unsigned char > pubkey , SigVersion sigversion , const ScriptExecutionData & execdata , ScriptError * serror ) const override { return true ; }
} ;
const DummySignatureChecker DUMMY_CHECKER ;
@ -439,6 +576,11 @@ public:
vchSig [ 6 + m_r_len + m_s_len ] = SIGHASH_ALL ;
return true ;
}
bool CreateSchnorrSig ( const SigningProvider & provider , std : : vector < unsigned char > & sig , const XOnlyPubKey & pubkey , const uint256 * leaf_hash , const uint256 * tweak , SigVersion sigversion ) const override
{
sig . assign ( 64 , ' \000 ' ) ;
return true ;
}
} ;
}