Pieter Wuille
11 years ago
6 changed files with 262 additions and 3 deletions
@ -0,0 +1,205 @@ |
|||||||
|
// Copyright (c) 2014 The Bitcoin developers
|
||||||
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include "sha1.h" |
||||||
|
|
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
// Internal implementation code.
|
||||||
|
namespace { |
||||||
|
|
||||||
|
/** Read 4 bytes, and interpret them as a 32-bit unsigned big-endian integer. */ |
||||||
|
uint32_t inline ReadBE32(const unsigned char *data) { |
||||||
|
return ((uint32_t)data[0] << 24 | (uint32_t)data[1] << 16 | (uint32_t)data[2] << 8 | (uint32_t)data[3]); |
||||||
|
} |
||||||
|
|
||||||
|
/** Write a 32-bit unsigned big-endian integer. */ |
||||||
|
void inline WriteBE32(unsigned char *data, uint32_t x) { |
||||||
|
data[0] = x >> 24; |
||||||
|
data[1] = x >> 16; |
||||||
|
data[2] = x >> 8; |
||||||
|
data[3] = x; |
||||||
|
} |
||||||
|
|
||||||
|
/// Internal SHA-1 implementation.
|
||||||
|
namespace sha1 { |
||||||
|
|
||||||
|
/** One round of SHA-1. */ |
||||||
|
void inline Round(uint32_t a, uint32_t &b, uint32_t c, uint32_t d, uint32_t &e, |
||||||
|
uint32_t f, uint32_t k, uint32_t w) { |
||||||
|
e += ((a << 5) | (a >> 27)) + f + k + w; |
||||||
|
b = (b << 30) | (b >> 2); |
||||||
|
} |
||||||
|
|
||||||
|
uint32_t inline f1(uint32_t b, uint32_t c, uint32_t d) { return d ^ (b & (c ^ d)); } |
||||||
|
uint32_t inline f2(uint32_t b, uint32_t c, uint32_t d) { return b ^ c ^ d; } |
||||||
|
uint32_t inline f3(uint32_t b, uint32_t c, uint32_t d) { return (b & c) | (d & (b | c)); } |
||||||
|
|
||||||
|
uint32_t inline left(uint32_t x) { return (x << 1) | (x >> 31); } |
||||||
|
|
||||||
|
/** Initialize SHA-1 state. */ |
||||||
|
void inline Initialize(uint32_t *s) { |
||||||
|
s[0] = 0x67452301ul; |
||||||
|
s[1] = 0xEFCDAB89ul; |
||||||
|
s[2] = 0x98BADCFEul; |
||||||
|
s[3] = 0x10325476ul; |
||||||
|
s[4] = 0xC3D2E1F0ul; |
||||||
|
} |
||||||
|
|
||||||
|
const uint32_t k1 = 0x5A827999ul; |
||||||
|
const uint32_t k2 = 0x6ED9EBA1ul; |
||||||
|
const uint32_t k3 = 0x8F1BBCDCul; |
||||||
|
const uint32_t k4 = 0xCA62C1D6ul; |
||||||
|
|
||||||
|
/** Perform a SHA-1 transformation, processing a 64-byte chunk. */ |
||||||
|
void Transform(uint32_t *s, const unsigned char *chunk) { |
||||||
|
uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4]; |
||||||
|
uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15; |
||||||
|
|
||||||
|
Round(a, b, c, d, e, f1(b, c, d), k1, w0 = ReadBE32(chunk + 0)); |
||||||
|
Round(e, a, b, c, d, f1(a, b, c), k1, w1 = ReadBE32(chunk + 4)); |
||||||
|
Round(d, e, a, b, c, f1(e, a, b), k1, w2 = ReadBE32(chunk + 8)); |
||||||
|
Round(c, d, e, a, b, f1(d, e, a), k1, w3 = ReadBE32(chunk + 12)); |
||||||
|
Round(b, c, d, e, a, f1(c, d, e), k1, w4 = ReadBE32(chunk + 16)); |
||||||
|
Round(a, b, c, d, e, f1(b, c, d), k1, w5 = ReadBE32(chunk + 20)); |
||||||
|
Round(e, a, b, c, d, f1(a, b, c), k1, w6 = ReadBE32(chunk + 24)); |
||||||
|
Round(d, e, a, b, c, f1(e, a, b), k1, w7 = ReadBE32(chunk + 28)); |
||||||
|
Round(c, d, e, a, b, f1(d, e, a), k1, w8 = ReadBE32(chunk + 32)); |
||||||
|
Round(b, c, d, e, a, f1(c, d, e), k1, w9 = ReadBE32(chunk + 36)); |
||||||
|
Round(a, b, c, d, e, f1(b, c, d), k1, w10 = ReadBE32(chunk + 40)); |
||||||
|
Round(e, a, b, c, d, f1(a, b, c), k1, w11 = ReadBE32(chunk + 44)); |
||||||
|
Round(d, e, a, b, c, f1(e, a, b), k1, w12 = ReadBE32(chunk + 48)); |
||||||
|
Round(c, d, e, a, b, f1(d, e, a), k1, w13 = ReadBE32(chunk + 52)); |
||||||
|
Round(b, c, d, e, a, f1(c, d, e), k1, w14 = ReadBE32(chunk + 56)); |
||||||
|
Round(a, b, c, d, e, f1(b, c, d), k1, w15 = ReadBE32(chunk + 60)); |
||||||
|
|
||||||
|
Round(e, a, b, c, d, f1(a, b, c), k1, w0 = left(w0 ^ w13 ^ w8 ^ w2 )); |
||||||
|
Round(d, e, a, b, c, f1(e, a, b), k1, w1 = left(w1 ^ w14 ^ w9 ^ w3 )); |
||||||
|
Round(c, d, e, a, b, f1(d, e, a), k1, w2 = left(w2 ^ w15 ^ w10 ^ w4 )); |
||||||
|
Round(b, c, d, e, a, f1(c, d, e), k1, w3 = left(w3 ^ w0 ^ w11 ^ w5 )); |
||||||
|
Round(a, b, c, d, e, f2(b, c, d), k2, w4 = left(w4 ^ w1 ^ w12 ^ w6 )); |
||||||
|
Round(e, a, b, c, d, f2(a, b, c), k2, w5 = left(w5 ^ w2 ^ w13 ^ w7 )); |
||||||
|
Round(d, e, a, b, c, f2(e, a, b), k2, w6 = left(w6 ^ w3 ^ w14 ^ w8 )); |
||||||
|
Round(c, d, e, a, b, f2(d, e, a), k2, w7 = left(w7 ^ w4 ^ w15 ^ w9 )); |
||||||
|
Round(b, c, d, e, a, f2(c, d, e), k2, w8 = left(w8 ^ w5 ^ w0 ^ w10)); |
||||||
|
Round(a, b, c, d, e, f2(b, c, d), k2, w9 = left(w9 ^ w6 ^ w1 ^ w11)); |
||||||
|
Round(e, a, b, c, d, f2(a, b, c), k2, w10 = left(w10 ^ w7 ^ w2 ^ w12)); |
||||||
|
Round(d, e, a, b, c, f2(e, a, b), k2, w11 = left(w11 ^ w8 ^ w3 ^ w13)); |
||||||
|
Round(c, d, e, a, b, f2(d, e, a), k2, w12 = left(w12 ^ w9 ^ w4 ^ w14)); |
||||||
|
Round(b, c, d, e, a, f2(c, d, e), k2, w13 = left(w13 ^ w10 ^ w5 ^ w15)); |
||||||
|
Round(a, b, c, d, e, f2(b, c, d), k2, w14 = left(w14 ^ w11 ^ w6 ^ w0 )); |
||||||
|
Round(e, a, b, c, d, f2(a, b, c), k2, w15 = left(w15 ^ w12 ^ w7 ^ w1 )); |
||||||
|
|
||||||
|
Round(d, e, a, b, c, f2(e, a, b), k2, w0 = left(w0 ^ w13 ^ w8 ^ w2 )); |
||||||
|
Round(c, d, e, a, b, f2(d, e, a), k2, w1 = left(w1 ^ w14 ^ w9 ^ w3 )); |
||||||
|
Round(b, c, d, e, a, f2(c, d, e), k2, w2 = left(w2 ^ w15 ^ w10 ^ w4 )); |
||||||
|
Round(a, b, c, d, e, f2(b, c, d), k2, w3 = left(w3 ^ w0 ^ w11 ^ w5 )); |
||||||
|
Round(e, a, b, c, d, f2(a, b, c), k2, w4 = left(w4 ^ w1 ^ w12 ^ w6 )); |
||||||
|
Round(d, e, a, b, c, f2(e, a, b), k2, w5 = left(w5 ^ w2 ^ w13 ^ w7 )); |
||||||
|
Round(c, d, e, a, b, f2(d, e, a), k2, w6 = left(w6 ^ w3 ^ w14 ^ w8 )); |
||||||
|
Round(b, c, d, e, a, f2(c, d, e), k2, w7 = left(w7 ^ w4 ^ w15 ^ w9 )); |
||||||
|
Round(a, b, c, d, e, f3(b, c, d), k3, w8 = left(w8 ^ w5 ^ w0 ^ w10)); |
||||||
|
Round(e, a, b, c, d, f3(a, b, c), k3, w9 = left(w9 ^ w6 ^ w1 ^ w11)); |
||||||
|
Round(d, e, a, b, c, f3(e, a, b), k3, w10 = left(w10 ^ w7 ^ w2 ^ w12)); |
||||||
|
Round(c, d, e, a, b, f3(d, e, a), k3, w11 = left(w11 ^ w8 ^ w3 ^ w13)); |
||||||
|
Round(b, c, d, e, a, f3(c, d, e), k3, w12 = left(w12 ^ w9 ^ w4 ^ w14)); |
||||||
|
Round(a, b, c, d, e, f3(b, c, d), k3, w13 = left(w13 ^ w10 ^ w5 ^ w15)); |
||||||
|
Round(e, a, b, c, d, f3(a, b, c), k3, w14 = left(w14 ^ w11 ^ w6 ^ w0 )); |
||||||
|
Round(d, e, a, b, c, f3(e, a, b), k3, w15 = left(w15 ^ w12 ^ w7 ^ w1 )); |
||||||
|
|
||||||
|
Round(c, d, e, a, b, f3(d, e, a), k3, w0 = left(w0 ^ w13 ^ w8 ^ w2 )); |
||||||
|
Round(b, c, d, e, a, f3(c, d, e), k3, w1 = left(w1 ^ w14 ^ w9 ^ w3 )); |
||||||
|
Round(a, b, c, d, e, f3(b, c, d), k3, w2 = left(w2 ^ w15 ^ w10 ^ w4 )); |
||||||
|
Round(e, a, b, c, d, f3(a, b, c), k3, w3 = left(w3 ^ w0 ^ w11 ^ w5 )); |
||||||
|
Round(d, e, a, b, c, f3(e, a, b), k3, w4 = left(w4 ^ w1 ^ w12 ^ w6 )); |
||||||
|
Round(c, d, e, a, b, f3(d, e, a), k3, w5 = left(w5 ^ w2 ^ w13 ^ w7 )); |
||||||
|
Round(b, c, d, e, a, f3(c, d, e), k3, w6 = left(w6 ^ w3 ^ w14 ^ w8 )); |
||||||
|
Round(a, b, c, d, e, f3(b, c, d), k3, w7 = left(w7 ^ w4 ^ w15 ^ w9 )); |
||||||
|
Round(e, a, b, c, d, f3(a, b, c), k3, w8 = left(w8 ^ w5 ^ w0 ^ w10)); |
||||||
|
Round(d, e, a, b, c, f3(e, a, b), k3, w9 = left(w9 ^ w6 ^ w1 ^ w11)); |
||||||
|
Round(c, d, e, a, b, f3(d, e, a), k3, w10 = left(w10 ^ w7 ^ w2 ^ w12)); |
||||||
|
Round(b, c, d, e, a, f3(c, d, e), k3, w11 = left(w11 ^ w8 ^ w3 ^ w13)); |
||||||
|
Round(a, b, c, d, e, f2(b, c, d), k4, w12 = left(w12 ^ w9 ^ w4 ^ w14)); |
||||||
|
Round(e, a, b, c, d, f2(a, b, c), k4, w13 = left(w13 ^ w10 ^ w5 ^ w15)); |
||||||
|
Round(d, e, a, b, c, f2(e, a, b), k4, w14 = left(w14 ^ w11 ^ w6 ^ w0 )); |
||||||
|
Round(c, d, e, a, b, f2(d, e, a), k4, w15 = left(w15 ^ w12 ^ w7 ^ w1 )); |
||||||
|
|
||||||
|
Round(b, c, d, e, a, f2(c, d, e), k4, w0 = left(w0 ^ w13 ^ w8 ^ w2 )); |
||||||
|
Round(a, b, c, d, e, f2(b, c, d), k4, w1 = left(w1 ^ w14 ^ w9 ^ w3 )); |
||||||
|
Round(e, a, b, c, d, f2(a, b, c), k4, w2 = left(w2 ^ w15 ^ w10 ^ w4 )); |
||||||
|
Round(d, e, a, b, c, f2(e, a, b), k4, w3 = left(w3 ^ w0 ^ w11 ^ w5 )); |
||||||
|
Round(c, d, e, a, b, f2(d, e, a), k4, w4 = left(w4 ^ w1 ^ w12 ^ w6 )); |
||||||
|
Round(b, c, d, e, a, f2(c, d, e), k4, w5 = left(w5 ^ w2 ^ w13 ^ w7 )); |
||||||
|
Round(a, b, c, d, e, f2(b, c, d), k4, w6 = left(w6 ^ w3 ^ w14 ^ w8 )); |
||||||
|
Round(e, a, b, c, d, f2(a, b, c), k4, w7 = left(w7 ^ w4 ^ w15 ^ w9 )); |
||||||
|
Round(d, e, a, b, c, f2(e, a, b), k4, w8 = left(w8 ^ w5 ^ w0 ^ w10)); |
||||||
|
Round(c, d, e, a, b, f2(d, e, a), k4, w9 = left(w9 ^ w6 ^ w1 ^ w11)); |
||||||
|
Round(b, c, d, e, a, f2(c, d, e), k4, w10 = left(w10 ^ w7 ^ w2 ^ w12)); |
||||||
|
Round(a, b, c, d, e, f2(b, c, d), k4, w11 = left(w11 ^ w8 ^ w3 ^ w13)); |
||||||
|
Round(e, a, b, c, d, f2(a, b, c), k4, w12 = left(w12 ^ w9 ^ w4 ^ w14)); |
||||||
|
Round(d, e, a, b, c, f2(e, a, b), k4, left(w13 ^ w10 ^ w5 ^ w15)); |
||||||
|
Round(c, d, e, a, b, f2(d, e, a), k4, left(w14 ^ w11 ^ w6 ^ w0 )); |
||||||
|
Round(b, c, d, e, a, f2(c, d, e), k4, left(w15 ^ w12 ^ w7 ^ w1 )); |
||||||
|
|
||||||
|
s[0] += a; |
||||||
|
s[1] += b; |
||||||
|
s[2] += c; |
||||||
|
s[3] += d; |
||||||
|
s[4] += e; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace sha1
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
////// SHA1
|
||||||
|
|
||||||
|
CSHA1::CSHA1() : bytes(0) { |
||||||
|
sha1::Initialize(s); |
||||||
|
} |
||||||
|
|
||||||
|
CSHA1& CSHA1::Write(const unsigned char *data, size_t len) { |
||||||
|
const unsigned char *end = data + len; |
||||||
|
size_t bufsize = bytes % 64; |
||||||
|
if (bufsize && bufsize + len >= 64) { |
||||||
|
// Fill the buffer, and process it.
|
||||||
|
memcpy(buf + bufsize, data, 64 - bufsize); |
||||||
|
bytes += 64 - bufsize; |
||||||
|
data += 64 - bufsize; |
||||||
|
sha1::Transform(s, buf); |
||||||
|
bufsize = 0; |
||||||
|
} |
||||||
|
while (end >= data + 64) { |
||||||
|
// Process full chunks directly from the source.
|
||||||
|
sha1::Transform(s, data); |
||||||
|
bytes += 64; |
||||||
|
data += 64; |
||||||
|
} |
||||||
|
if (end > data) { |
||||||
|
// Fill the buffer with what remains.
|
||||||
|
memcpy(buf + bufsize, data, end - data); |
||||||
|
bytes += end - data; |
||||||
|
} |
||||||
|
return *this; |
||||||
|
} |
||||||
|
|
||||||
|
void CSHA1::Finalize(unsigned char *hash) { |
||||||
|
static const unsigned char pad[64] = {0x80}; |
||||||
|
unsigned char sizedesc[8]; |
||||||
|
WriteBE32(sizedesc, bytes >> 29); |
||||||
|
WriteBE32(sizedesc+4, bytes << 3); |
||||||
|
Write(pad, 1 + ((119 - (bytes % 64)) % 64)); |
||||||
|
Write(sizedesc, 8); |
||||||
|
WriteBE32(hash, s[0]); |
||||||
|
WriteBE32(hash+4, s[1]); |
||||||
|
WriteBE32(hash+8, s[2]); |
||||||
|
WriteBE32(hash+12, s[3]); |
||||||
|
WriteBE32(hash+16, s[4]); |
||||||
|
} |
||||||
|
|
||||||
|
CSHA1& CSHA1::Reset() { |
||||||
|
bytes = 0; |
||||||
|
sha1::Initialize(s); |
||||||
|
return *this; |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
// Copyright (c) 2014 The Bitcoin developers
|
||||||
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#ifndef BITCOIN_SHA1_H |
||||||
|
#define BITCOIN_SHA1_H |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
#include <stdlib.h> |
||||||
|
|
||||||
|
/** A hasher class for SHA1. */ |
||||||
|
class CSHA1 { |
||||||
|
private: |
||||||
|
uint32_t s[5]; |
||||||
|
unsigned char buf[64]; |
||||||
|
size_t bytes; |
||||||
|
|
||||||
|
public: |
||||||
|
CSHA1(); |
||||||
|
CSHA1& Write(const unsigned char *data, size_t len); |
||||||
|
void Finalize(unsigned char *hash); |
||||||
|
CSHA1& Reset(); |
||||||
|
}; |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,27 @@ |
|||||||
|
// Copyright (c) 2014 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include "sha1.h" |
||||||
|
#include "util.h" |
||||||
|
|
||||||
|
#include <vector> |
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp> |
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE(sha1_tests) |
||||||
|
|
||||||
|
void SHA1TestVector(const std::string &in, const std::string &out) { |
||||||
|
std::vector<unsigned char> hash; |
||||||
|
hash.resize(20); |
||||||
|
CSHA1().Write((unsigned char*)&in[0], in.size()).Finalize(&hash[0]); |
||||||
|
BOOST_CHECK_EQUAL(HexStr(hash), out); |
||||||
|
} |
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(sha1_testvectors) { |
||||||
|
SHA1TestVector("abc", "a9993e364706816aba3e25717850c26c9cd0d89d"); |
||||||
|
SHA1TestVector("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "84983e441c3bd26ebaae4aa1f95129e5e54670f1"); |
||||||
|
SHA1TestVector(std::string(1000000, 'a'), "34aa973cd4c4daa4f61eeb2bdbad27316534016f"); |
||||||
|
} |
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END() |
Loading…
Reference in new issue