aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2014-04-28 03:09:13 +0200
committerPieter Wuille <pieter.wuille@gmail.com>2014-06-21 19:47:39 +0200
commit1cc344ce42d8dddd6356c89ef3ceb58418676816 (patch)
tree36577c13adeaa82a546e3d9b5a6bb37c45c180f1
parent85aab2a08824a83a535e6dfee4c150b25ebaf9de (diff)
Add built-in SHA-1 implementation.
-rw-r--r--src/Makefile.am2
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/script.cpp5
-rw-r--r--src/sha1.cpp205
-rw-r--r--src/sha1.h25
-rw-r--r--src/test/sha1_tests.cpp27
6 files changed, 262 insertions, 3 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 4e94d47066..67b069bde1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -76,6 +76,7 @@ BITCOIN_CORE_H = \
script.h \
serialize.h \
sha2.h \
+ sha1.h \
sync.h \
threadsafety.h \
tinyformat.h \
@@ -153,6 +154,7 @@ libbitcoin_common_a_SOURCES = \
protocol.cpp \
rpcprotocol.cpp \
script.cpp \
+ sha1.cpp \
sha2.cpp \
sync.cpp \
util.cpp \
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 93723309af..7cf441bd6c 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -45,6 +45,7 @@ BITCOIN_TESTS =\
test/script_P2SH_tests.cpp \
test/script_tests.cpp \
test/serialize_tests.cpp \
+ test/sha1_tests.cpp \
test/sha2_tests.cpp \
test/sigopcount_tests.cpp \
test/test_bitcoin.cpp \
diff --git a/src/script.cpp b/src/script.cpp
index f20c0bcca3..facf3044d6 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -9,13 +9,12 @@
#include "hash.h"
#include "key.h"
#include "keystore.h"
+#include "sha1.h"
#include "sha2.h"
#include "sync.h"
#include "uint256.h"
#include "util.h"
-#include <openssl/sha.h>
-
#include <boost/foreach.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
@@ -806,7 +805,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co
if (opcode == OP_RIPEMD160)
RIPEMD160(&vch[0], vch.size(), &vchHash[0]);
else if (opcode == OP_SHA1)
- SHA1(&vch[0], vch.size(), &vchHash[0]);
+ CSHA1().Write(&vch[0], vch.size()).Finalize(&vchHash[0]);
else if (opcode == OP_SHA256)
CSHA256().Write(&vch[0], vch.size()).Finalize(&vchHash[0]);
else if (opcode == OP_HASH160)
diff --git a/src/sha1.cpp b/src/sha1.cpp
new file mode 100644
index 0000000000..0a70077544
--- /dev/null
+++ b/src/sha1.cpp
@@ -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;
+}
diff --git a/src/sha1.h b/src/sha1.h
new file mode 100644
index 0000000000..6efde78a5b
--- /dev/null
+++ b/src/sha1.h
@@ -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
diff --git a/src/test/sha1_tests.cpp b/src/test/sha1_tests.cpp
new file mode 100644
index 0000000000..bae17c5d4a
--- /dev/null
+++ b/src/test/sha1_tests.cpp
@@ -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()