dogecoin/src/test/canonical_tests.cpp
Pieter Wuille 6fd7ef2bbf Also switch the (unused) verification code to low-s instead of even-s.
a81cd968 introduced a malleability breaker for signatures
(using an even value for S). In e0e14e43 this was changed to
the lower of two potential values, rather than the even one.
Only the signing code was changed though, the (for now unused)
verification code wasn't adapted.
2014-03-10 20:38:32 +01:00

110 lines
3.2 KiB
C++

//
// Unit tests for canonical signatures
//
#include "script.h"
#include "util.h"
#include "data/sig_noncanonical.json.h"
#include "data/sig_canonical.json.h"
#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
#include "json/json_spirit_writer_template.h"
#include <openssl/ecdsa.h>
using namespace std;
using namespace json_spirit;
// In script_tests.cpp
extern Array read_json(const std::string& jsondata);
BOOST_AUTO_TEST_SUITE(canonical_tests)
// OpenSSL-based test for canonical signature (without test for hashtype byte)
bool static IsCanonicalSignature_OpenSSL_inner(const std::vector<unsigned char>& vchSig)
{
if (vchSig.size() == 0)
return false;
const unsigned char *input = &vchSig[0];
ECDSA_SIG *psig = NULL;
d2i_ECDSA_SIG(&psig, &input, vchSig.size());
if (psig == NULL)
return false;
unsigned char buf[256];
unsigned char *pbuf = buf;
unsigned int nLen = i2d_ECDSA_SIG(psig, NULL);
if (nLen != vchSig.size()) {
ECDSA_SIG_free(psig);
return false;
}
nLen = i2d_ECDSA_SIG(psig, &pbuf);
ECDSA_SIG_free(psig);
return (memcmp(&vchSig[0], &buf[0], nLen) == 0);
}
// OpenSSL-based test for canonical signature
bool static IsCanonicalSignature_OpenSSL(const std::vector<unsigned char> &vchSignature) {
if (vchSignature.size() < 1)
return false;
if (vchSignature.size() > 127)
return false;
if (vchSignature[vchSignature.size() - 1] & 0x7C)
return false;
std::vector<unsigned char> vchSig(vchSignature);
vchSig.pop_back();
if (!IsCanonicalSignature_OpenSSL_inner(vchSig))
return false;
return true;
}
BOOST_AUTO_TEST_CASE(script_canon)
{
Array tests = read_json(std::string(json_tests::sig_canonical, json_tests::sig_canonical + sizeof(json_tests::sig_canonical)));
BOOST_FOREACH(Value &tv, tests) {
string test = tv.get_str();
if (IsHex(test)) {
std::vector<unsigned char> sig = ParseHex(test);
BOOST_CHECK_MESSAGE(IsCanonicalSignature(sig, SCRIPT_VERIFY_STRICTENC), test);
BOOST_CHECK_MESSAGE(IsCanonicalSignature_OpenSSL(sig), test);
}
}
}
BOOST_AUTO_TEST_CASE(script_noncanon)
{
Array tests = read_json(std::string(json_tests::sig_noncanonical, json_tests::sig_noncanonical + sizeof(json_tests::sig_noncanonical)));
BOOST_FOREACH(Value &tv, tests) {
string test = tv.get_str();
if (IsHex(test)) {
std::vector<unsigned char> sig = ParseHex(test);
BOOST_CHECK_MESSAGE(!IsCanonicalSignature(sig, SCRIPT_VERIFY_STRICTENC), test);
BOOST_CHECK_MESSAGE(!IsCanonicalSignature_OpenSSL(sig), test);
}
}
}
BOOST_AUTO_TEST_CASE(script_signstrict)
{
for (int i=0; i<100; i++) {
CKey key;
key.MakeNewKey(i & 1);
std::vector<unsigned char> sig;
uint256 hash = GetRandHash();
BOOST_CHECK(key.Sign(hash, sig)); // Generate a random signature.
BOOST_CHECK(key.GetPubKey().Verify(hash, sig)); // Check it.
sig.push_back(0x01); // Append a sighash type.
BOOST_CHECK(IsCanonicalSignature(sig, SCRIPT_VERIFY_STRICTENC | SCRIPT_VERIFY_LOW_S));
BOOST_CHECK(IsCanonicalSignature_OpenSSL(sig));
}
}
BOOST_AUTO_TEST_SUITE_END()