Changeset View
Changeset View
Standalone View
Standalone View
src/script/sigencoding.cpp
// Copyright (c) 2009-2010 Satoshi Nakamoto | // Copyright (c) 2009-2010 Satoshi Nakamoto | ||||
// Copyright (c) 2009-2016 The Bitcoin Core developers | // Copyright (c) 2009-2016 The Bitcoin Core developers | ||||
// Copyright (c) 2017-2018 The Bitcoin developers | // Copyright (c) 2017-2018 The Bitcoin developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include "sigencoding.h" | #include "sigencoding.h" | ||||
#include "pubkey.h" | #include "pubkey.h" | ||||
#include "script_flags.h" | #include "script_flags.h" | ||||
#include <boost/range/adaptor/sliced.hpp> | #include <boost/range/adaptor/sliced.hpp> | ||||
typedef boost::sliced_range<const valtype> slicedvaltype; | |||||
/** | /** | ||||
* A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len | * A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len | ||||
* S> <S> <hashtype>, where R and S are not negative (their first byte has its | * S> <S> <hashtype>, where R and S are not negative (their first byte has its | ||||
* highest bit not set), and not excessively padded (do not start with a 0 byte, | * highest bit not set), and not excessively padded (do not start with a 0 byte, | ||||
* unless an otherwise negative number follows, in which case a single 0 byte is | * unless an otherwise negative number follows, in which case a single 0 byte is | ||||
* necessary and even required). | * necessary and even required). | ||||
* | * | ||||
* See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623 | * See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623 | ||||
* | * | ||||
* This function is consensus-critical since BIP66. | * This function is consensus-critical since BIP66. | ||||
*/ | */ | ||||
static bool | static bool IsValidSignatureEncoding(const slicedvaltype &sig) { | ||||
IsValidSignatureEncoding(const boost::sliced_range<const valtype> &sig) { | |||||
// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] | // Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] | ||||
// * total-length: 1-byte length descriptor of everything that follows, | // * total-length: 1-byte length descriptor of everything that follows, | ||||
// excluding the sighash byte. | // excluding the sighash byte. | ||||
// * R-length: 1-byte length descriptor of the R value that follows. | // * R-length: 1-byte length descriptor of the R value that follows. | ||||
// * R: arbitrary-length big-endian encoded R value. It must use the | // * R: arbitrary-length big-endian encoded R value. It must use the | ||||
// shortest possible encoding for a positive integers (which means no null | // shortest possible encoding for a positive integers (which means no null | ||||
// bytes at the start, except a single one when the next byte has its | // bytes at the start, except a single one when the next byte has its | ||||
// highest bit set). | // highest bit set). | ||||
▲ Show 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | static bool IsValidSignatureEncoding(const slicedvaltype &sig) { | ||||
// our of bound elements. | // our of bound elements. | ||||
if (lenS > 1 && (sig[startS + 2] == 0x00) && !(sig[startS + 3] & 0x80)) { | if (lenS > 1 && (sig[startS + 2] == 0x00) && !(sig[startS + 3] & 0x80)) { | ||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
static bool IsLowDERSignature(const valtype &vchSig, ScriptError *serror) { | static bool CheckSignatureWithoutSigHashTypeEncoding(const slicedvaltype &sig, | ||||
assert(vchSig.size() > 0); | uint32_t flags, | ||||
if (CPubKey::CheckLowS(vchSig | | ScriptError *serror) { | ||||
boost::adaptors::sliced(0, vchSig.size() - 1))) { | if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | | ||||
return true; | SCRIPT_VERIFY_STRICTENC)) && | ||||
!IsValidSignatureEncoding(sig)) { | |||||
return set_error(serror, SCRIPT_ERR_SIG_DER); | |||||
} | } | ||||
if ((flags & SCRIPT_VERIFY_LOW_S) && !CPubKey::CheckLowS(sig)) { | |||||
return set_error(serror, SCRIPT_ERR_SIG_HIGH_S); | return set_error(serror, SCRIPT_ERR_SIG_HIGH_S); | ||||
} | } | ||||
bool CheckSignatureEncoding(const valtype &vchSig, uint32_t flags, | return true; | ||||
} | |||||
bool CheckTransactionSignatureEncoding(const valtype &vchSig, uint32_t flags, | |||||
ScriptError *serror) { | ScriptError *serror) { | ||||
// Empty signature. Not strictly DER encoded, but allowed to provide a | // Empty signature. Not strictly DER encoded, but allowed to provide a | ||||
// compact way to provide an invalid signature for use with CHECK(MULTI)SIG | // compact way to provide an invalid signature for use with CHECK(MULTI)SIG | ||||
if (vchSig.size() == 0) { | if (vchSig.size() == 0) { | ||||
return true; | return true; | ||||
} | } | ||||
if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | | |||||
SCRIPT_VERIFY_STRICTENC)) != 0 && | if (!CheckSignatureWithoutSigHashTypeEncoding( | ||||
!IsValidSignatureEncoding( | vchSig | boost::adaptors::sliced(0, vchSig.size() - 1), flags, | ||||
vchSig | boost::adaptors::sliced(0, vchSig.size() - 1))) { | serror)) { | ||||
return set_error(serror, SCRIPT_ERR_SIG_DER); | |||||
} | |||||
if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && | |||||
!IsLowDERSignature(vchSig, serror)) { | |||||
// serror is set | // serror is set | ||||
return false; | return false; | ||||
} | } | ||||
if ((flags & SCRIPT_VERIFY_STRICTENC) != 0) { | if ((flags & SCRIPT_VERIFY_STRICTENC) != 0) { | ||||
if (!GetHashType(vchSig).isDefined()) { | if (!GetHashType(vchSig).isDefined()) { | ||||
return set_error(serror, SCRIPT_ERR_SIG_HASHTYPE); | return set_error(serror, SCRIPT_ERR_SIG_HASHTYPE); | ||||
} | } | ||||
bool usesForkId = GetHashType(vchSig).hasForkId(); | bool usesForkId = GetHashType(vchSig).hasForkId(); | ||||
bool forkIdEnabled = flags & SCRIPT_ENABLE_SIGHASH_FORKID; | bool forkIdEnabled = flags & SCRIPT_ENABLE_SIGHASH_FORKID; | ||||
if (!forkIdEnabled && usesForkId) { | if (!forkIdEnabled && usesForkId) { | ||||
return set_error(serror, SCRIPT_ERR_ILLEGAL_FORKID); | return set_error(serror, SCRIPT_ERR_ILLEGAL_FORKID); | ||||
▲ Show 20 Lines • Show All 50 Lines • Show Last 20 Lines |