diff --git a/src/avalanche/processor.cpp b/src/avalanche/processor.cpp --- a/src/avalanche/processor.cpp +++ b/src/avalanche/processor.cpp @@ -222,12 +222,7 @@ const uint256 hash = hasher.GetHash(); // Now let's sign! - std::vector vchSig; - if (key.SignSchnorr(hash, vchSig)) { - // Schnorr sigs are 64 bytes in size. - assert(vchSig.size() == 64); - std::copy(vchSig.begin(), vchSig.end(), sig.begin()); - } else { + if (!key.SignSchnorr(hash, sig)) { sig.fill(0); } } diff --git a/src/avalanche/proof.cpp b/src/avalanche/proof.cpp --- a/src/avalanche/proof.cpp +++ b/src/avalanche/proof.cpp @@ -21,9 +21,7 @@ } bool SignedStake::verify(const ProofId &proofid) const { - // Unfortunately, the verify API require a vector. - std::vector vchSig{sig.begin(), sig.end()}; - return stake.getPubkey().VerifySchnorr(stake.getHash(proofid), vchSig); + return stake.getPubkey().VerifySchnorr(stake.getHash(proofid), sig); } ProofId Proof::computeProofId() const { diff --git a/src/avalanche/proofbuilder.cpp b/src/avalanche/proofbuilder.cpp --- a/src/avalanche/proofbuilder.cpp +++ b/src/avalanche/proofbuilder.cpp @@ -12,12 +12,7 @@ const uint256 h = stake.getHash(proofid); std::array sig; - std::vector vchSig; - if (key.SignSchnorr(h, vchSig)) { - // Schnorr sig are always 64 bytes in size. - assert(vchSig.size() == 64); - std::copy(vchSig.begin(), vchSig.end(), sig.begin()); - } else { + if (!key.SignSchnorr(h, sig)) { sig.fill(0); } diff --git a/src/key.h b/src/key.h --- a/src/key.h +++ b/src/key.h @@ -120,6 +120,9 @@ * Create a Schnorr signature. * The test_case parameter tweaks the deterministic nonce. */ + bool SignSchnorr(const uint256 &hash, + std::array &sig, + uint32_t test_case = 0) const; bool SignSchnorr(const uint256 &hash, std::vector &vchSig, uint32_t test_case = 0) const; diff --git a/src/key.cpp b/src/key.cpp --- a/src/key.cpp +++ b/src/key.cpp @@ -269,22 +269,37 @@ return true; } -bool CKey::SignSchnorr(const uint256 &hash, std::vector &vchSig, - uint32_t test_case) const { - if (!fValid) { +static bool DoSignSchnorr(const CKey &key, const uint256 &hash, uint8_t *buf, + uint32_t test_case) { + if (!key.IsValid()) { return false; } - vchSig.resize(64); + uint8_t extra_entropy[32] = {0}; WriteLE32(extra_entropy, test_case); int ret = secp256k1_schnorr_sign( - secp256k1_context_sign, &vchSig[0], hash.begin(), begin(), + secp256k1_context_sign, buf, hash.begin(), key.begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : nullptr); assert(ret); return true; } +bool CKey::SignSchnorr(const uint256 &hash, + std::array &sig, + uint32_t test_case) const { + return DoSignSchnorr(*this, hash, sig.data(), test_case); +} + +bool CKey::SignSchnorr(const uint256 &hash, std::vector &vchSig, + uint32_t test_case) const { + if (!fValid) { + return false; + } + vchSig.resize(CPubKey::SCHNORR_SIZE); + return DoSignSchnorr(*this, hash, vchSig.data(), test_case); +} + bool CKey::VerifyPubKey(const CPubKey &pubkey) const { if (pubkey.IsCompressed() != fCompressed) { return false; diff --git a/src/net_processing.cpp b/src/net_processing.cpp --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -3870,10 +3870,7 @@ if (!g_avalanche->forNode(pfrom.GetId(), [&](const avalanche::Node &n) { std::array sig; vRecv >> sig; - - // Unfortunately, the verify API require a vector. - std::vector vchSig{sig.begin(), sig.end()}; - return n.pubkey.VerifySchnorr(verifier.GetHash(), vchSig); + return n.pubkey.VerifySchnorr(verifier.GetHash(), sig); })) { LOCK(cs_main); Misbehaving(pfrom, 100, "invalid-ava-response-signature"); diff --git a/src/pubkey.h b/src/pubkey.h --- a/src/pubkey.h +++ b/src/pubkey.h @@ -25,7 +25,7 @@ explicit CKeyID(const uint160 &in) : uint160(in) {} }; -typedef uint256 ChainCode; +using ChainCode = uint256; /** An encapsulated public key. */ class CPubKey { @@ -35,6 +35,7 @@ */ static constexpr unsigned int SIZE = 65; static constexpr unsigned int COMPRESSED_SIZE = 33; + static constexpr unsigned int SCHNORR_SIZE = 64; static constexpr unsigned int SIGNATURE_SIZE = 72; static constexpr unsigned int COMPACT_SIGNATURE_SIZE = 65; /** @@ -163,6 +164,8 @@ * 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::array &sig) const; bool VerifySchnorr(const uint256 &hash, const std::vector &vchSig) const; diff --git a/src/pubkey.cpp b/src/pubkey.cpp --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -197,26 +197,34 @@ &pubkey); } -bool CPubKey::VerifySchnorr(const uint256 &hash, - const std::vector &vchSig) const { +bool CPubKey::VerifySchnorr( + const uint256 &hash, const std::array &sig) 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.data(), + return secp256k1_schnorr_verify(secp256k1_context_verify, sig.data(), hash.begin(), &pubkey); } +bool CPubKey::VerifySchnorr(const uint256 &hash, + const std::vector &vchSig) const { + if (vchSig.size() != SCHNORR_SIZE) { + return false; + } + + std::array sig; + std::copy(vchSig.begin(), vchSig.end(), sig.begin()); + + return VerifySchnorr(hash, sig); +} + bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector &vchSig) { if (vchSig.size() != COMPACT_SIGNATURE_SIZE) {