diff --git a/src/key.h b/src/key.h --- a/src/key.h +++ b/src/key.h @@ -113,6 +113,13 @@ bool SignECDSA(const uint256 &hash, std::vector &vchSig, uint32_t test_case = 0) const; + /** + * Create a Schnorr signature. + * The test_case parameter tweaks the deterministic nonce. + */ + bool SignSchnorr(const uint256 &hash, std::vector &vchSig, + uint32_t test_case = 0) const; + /** * Create a compact ECDSA signature (65 bytes), which allows reconstructing * the used public key. diff --git a/src/key.cpp b/src/key.cpp --- a/src/key.cpp +++ b/src/key.cpp @@ -12,6 +12,7 @@ #include #include +#include static secp256k1_context *secp256k1_context_sign = nullptr; @@ -201,6 +202,25 @@ return true; } +bool CKey::SignSchnorr(const uint256 &hash, std::vector &vchSig, + uint32_t test_case) const { + if (!fValid) return false; + vchSig.resize(64); + uint8_t extra_entropy[32] = {0}; + WriteLE32(extra_entropy, test_case); + + secp256k1_pubkey pubkey; + int retp = + secp256k1_ec_pubkey_create(secp256k1_context_sign, &pubkey, begin()); + assert(retp); + + int ret = secp256k1_schnorr_sign( + secp256k1_context_sign, &vchSig[0], hash.begin(), begin(), &pubkey, + secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : nullptr); + assert(ret); + return true; +} + bool CKey::VerifyPubKey(const CPubKey &pubkey) const { if (pubkey.IsCompressed() != fCompressed) { return false; diff --git a/src/pubkey.h b/src/pubkey.h --- a/src/pubkey.h +++ b/src/pubkey.h @@ -142,6 +142,13 @@ bool VerifyECDSA(const uint256 &hash, const std::vector &vchSig) const; + /** + * Verify a Schnorr signature (=64 bytes). + * If this public key is not fully valid, the return value will be false. + */ + bool VerifySchnorr(const uint256 &hash, + const std::vector &vchSig) const; + /** * Check whether a DER-serialized ECDSA signature is normalized (lower-S). */ diff --git a/src/pubkey.cpp b/src/pubkey.cpp --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -6,6 +6,7 @@ #include #include +#include namespace { /* Global secp256k1_context object used for verification. */ @@ -194,6 +195,26 @@ &pubkey); } +bool CPubKey::VerifySchnorr(const uint256 &hash, + const std::vector &vchSig) const { + if (!IsValid()) { + return false; + } + + if (vchSig.size() != 64) { + return false; + } + + secp256k1_pubkey pubkey; + if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, + &(*this)[0], size())) { + return false; + } + + return secp256k1_schnorr_verify(secp256k1_context_verify, &vchSig[0], + hash.begin(), &pubkey); +} + bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector &vchSig) { if (vchSig.size() != 65) {