Created
January 14, 2015 09:25
-
-
Save theuni/a64d9fd70fb7eab03186 to your computer and use it in GitHub Desktop.
dersig constexpr evaluation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Compile with: g++ -std=c++11 dersig.cpp -o dersig | |
#include <cstddef> | |
#include <vector> | |
#include <array> | |
inline constexpr char getHex(const char in) | |
{ | |
return in >= '0' && in <= '9' ? in - '0' : | |
in >= 'A' && in <= 'F' ? in - 'A' + 10 : | |
in >= 'a' && in <= 'f' ? in - 'a' + 10 : -1; | |
} | |
template <size_t Length> | |
inline constexpr unsigned char getElem(const std::array<char, Length>& sig, unsigned int elem) | |
{ | |
return static_cast<unsigned char>(getHex(sig.at((elem*2)+2)) << 4 | ( (elem*2)+3 < sig.size() ? getHex(sig.at((elem*2)+3)) : 0)); | |
} | |
template <size_t Length> | |
inline constexpr unsigned int lenR(const std::array<char, Length>& sig) | |
{ | |
return getElem(sig, 3); | |
} | |
template <size_t Length> | |
inline constexpr unsigned int lenS(const std::array<char, Length>& sig) | |
{ | |
return getElem(sig, 5 + lenR(sig)); | |
} | |
template <size_t Length> | |
inline constexpr size_t sigSize(const std::array<char, Length>& sig) | |
{ | |
return (sig.size() - 1) / 2; | |
} | |
template <size_t Length> | |
inline constexpr bool IsDERSignature(const std::array<char, Length> sig) | |
{ | |
// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash] | |
// * total-length: 1-byte length descriptor of everything that follows, | |
// excluding the sighash byte. | |
// * R-length: 1-byte length descriptor of the R value that follows. | |
// * R: arbitrary-length big-endian encoded R value. It cannot start with any | |
// null bytes, unless the first byte that follows is 0x80 or higher, in which | |
// case a single null byte is required. | |
// * S-length: 1-byte length descriptor of the S value that follows. | |
// * S: arbitrary-length big-endian encoded S value. The same rules apply. | |
// * sighash: 1-byte value indicating what data is hashed. | |
// Accept empty signature as correctly encoded (but invalid) signature, | |
// even though it is not strictly DER. | |
return (sigSize(sig) == 0) || | |
( | |
// Minimum and maximum size constraints. | |
sigSize(sig) >= 9 && sigSize(sig) <= 73 && | |
// A signature is of type 0x30 (compound). | |
getElem(sig,0) == 0x30 && | |
// Make sure the length covers the entire signature. | |
getElem(sig,1) == sigSize(sig) - 3 && | |
// Make sure the length of the S element is still inside the signature. | |
lenR(sig) + 5 < sigSize(sig) && | |
// Verify that the length of the signature matches the sum of the length | |
// of the elements. | |
static_cast<size_t>(lenS(sig) + lenR(sig) + 7) == sigSize(sig) && | |
// Check whether the R element is an integer. | |
getElem(sig,2) == 0x02 && | |
// Zero-length integers are not allowed for R. | |
lenR(sig) != 0 && | |
// Negative numbers are not allowed for R. | |
(getElem(sig,4) & 0x80) == 0 && | |
// Zero bytes at the start of R are not allowed, unless it would | |
// otherwise be interpreted as a negative number. | |
!(lenR(sig) > 1 && (getElem(sig,4) == 0x00) && !(getElem(sig,5) & 0x80)) && | |
// Check whether the S element is an integer. | |
getElem(sig,lenR(sig) + 4) == 0x02 && | |
// Zero-length integers are not allowed for S. | |
lenS(sig) != 0 && | |
// Negative numbers are not allowed for S. | |
(getElem(sig,lenR(sig) + 6) & 0x80) == 0 && | |
// Null bytes at the start of R are not allowed, unless it would otherwise be | |
// interpreted as a negative number. | |
!(lenS(sig) > 1 && (getElem(sig,lenR(sig) + 6) == 0x00) && !(getElem(sig,lenR(sig) + 7) & 0x80)) | |
); | |
} | |
template <char... Args> | |
std::vector<unsigned char> operator "" _der() | |
{ | |
constexpr std::array<char, sizeof...(Args)> temp{{Args...}}; | |
static_assert(IsDERSignature(std::array<char,temp.size()>(temp)), "invalid der"); | |
std::vector<unsigned char> ret(sigSize(temp)); | |
for (auto i : ret) | |
ret[i] = getElem(temp, i); | |
return ret; | |
} | |
int main() | |
{ | |
typedef std::vector<unsigned char> der_type; | |
der_type foo = 0x304402202cb265bf10707bf49346c3515dd3d16fc454618c58ec0a0ff448a676c54ff71302206c6624d762a1fcef4618284ead8f08678ac05b13c84235f1654e6ad168233e8201_der; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment