llvm.org GIT mirror llvm / 74c634c
Add support for computing SHA1 in LLVM Provide a class to generate a SHA1 from a sequence of bytes, and a convenience raw_ostream adaptor. This will be used to provide a "build-id" by hashing the Module block when writing bitcode. ThinLTO will use this information for incremental build. Reapply r265094 which was reverted in r265102 because it broke MSVC bots (constexpr is not supported). http://reviews.llvm.org/D16325 From: Mehdi Amini <mehdi.amini@apple.com> git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@265107 91177308-0d34-0410-b5e6-96231b3b80d8 Mehdi Amini 3 years ago
6 changed file(s) with 363 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 //==- SHA1.h - SHA1 implementation for LLVM --*- C++ -*-==//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 // This code is taken from public domain
9 // (http://oauth.googlecode.com/svn/code/c/liboauth/src/sha1.c)
10 // and modified by wrapping it in a C++ interface for LLVM,
11 // and removing unnecessary code.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #ifndef LLVM_SUPPORT_SHA1_H
16 #define LLVM_SUPPORT_SHA1_H
17
18 #include "llvm/ADT/ArrayRef.h"
19 #include "llvm/ADT/StringRef.h"
20
21 #include
22
23 namespace llvm {
24
25 /// A class that wrap the SHA1 algorithm.
26 class SHA1 {
27 public:
28 SHA1() { init(); }
29
30 /// Reinitialize the internal state
31 void init();
32
33 /// Digest more data.
34 void update(ArrayRef Data);
35
36 /// Return a reference to the current raw 160-bits SHA1 for the digested data
37 /// since the last call to init(). This call will add data to the internal
38 /// state and as such is not suited for getting an intermediate result
39 /// (see result()).
40 StringRef final();
41
42 /// Return a reference to the current raw 160-bits SHA1 for the digested data
43 /// since the last call to init(). This is suitable for getting the SHA1 at
44 /// any time without invalidating the internal state so that more calls can be
45 /// made into update.
46 StringRef result();
47
48 private:
49 /// Define some constants.
50 /// "static constexpr" would be cleaner but MSVC does not support it yet.
51 enum { BLOCK_LENGTH = 64 };
52 enum { HASH_LENGTH = 20 };
53
54 // Internal State
55 struct {
56 uint32_t Buffer[BLOCK_LENGTH / 4];
57 uint32_t State[HASH_LENGTH / 4];
58 uint32_t ByteCount;
59 uint8_t BufferOffset;
60 } InternalState;
61
62 // Internal copy of the hash, populated and accessed on calls to result()
63 uint32_t HashResult[HASH_LENGTH / 4];
64
65 // Helper
66 void writebyte(uint8_t data);
67 void hashBlock();
68 void addUncounted(uint8_t data);
69 void pad();
70 };
71
72 } // end llvm namespace
73
74 #endif
0 //==- raw_sha1_ostream.h - raw_ostream that compute SHA1 --*- C++ -*-==//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines the raw_sha1_ostream class.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_SUPPORT_RAW_SHA1_OSTREAM_H
14 #define LLVM_SUPPORT_RAW_SHA1_OSTREAM_H
15
16 #include "llvm/Support/raw_ostream.h"
17 #include "llvm/Support/SHA1.h"
18
19 namespace llvm {
20
21 /// A raw_ostream that hash the content using the sha1 algorithm.
22 class raw_sha1_ostream : public raw_ostream {
23 SHA1 State;
24
25 /// See raw_ostream::write_impl.
26 void write_impl(const char *Ptr, size_t Size) override {
27 State.update(ArrayRef((uint8_t *)Ptr, Size));
28 }
29
30 public:
31 /// Return the current SHA1 hash for the content of the stream
32 StringRef sha1() {
33 flush();
34 return State.result();
35 }
36
37 /// Reset the internal state to start over from scratch.
38 void resetHash() { State.init(); }
39
40 uint64_t current_pos() const override { return 0; }
41 };
42
43 } // end llvm namespace
44
45 #endif
7474 RandomNumberGenerator.cpp
7575 Regex.cpp
7676 ScaledNumber.cpp
77 SHA1.cpp
7778 SmallPtrSet.cpp
7879 SmallVector.cpp
7980 SourceMgr.cpp
0 //======- SHA1.h - Private copy of the SHA1 implementation ---*- C++ -* ======//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 // This code is taken from public domain
9 // (http://oauth.googlecode.com/svn/code/c/liboauth/src/sha1.c)
10 // and modified by wrapping it in a C++ interface for LLVM,
11 // and removing unnecessary code.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "llvm/Support/SHA1.h"
16 using namespace llvm;
17
18 #include
19 #include
20
21 #ifdef __BIG_ENDIAN__
22 #define SHA_BIG_ENDIAN
23 #endif
24
25 /* code */
26 #define SHA1_K0 0x5a827999
27 #define SHA1_K20 0x6ed9eba1
28 #define SHA1_K40 0x8f1bbcdc
29 #define SHA1_K60 0xca62c1d6
30
31 #define SEED_0 0x67452301
32 #define SEED_1 0xefcdab89
33 #define SEED_2 0x98badcfe
34 #define SEED_3 0x10325476
35 #define SEED_4 0xc3d2e1f0
36
37 void SHA1::init() {
38 InternalState.State[0] = SEED_0;
39 InternalState.State[1] = SEED_1;
40 InternalState.State[2] = SEED_2;
41 InternalState.State[3] = SEED_3;
42 InternalState.State[4] = SEED_4;
43 InternalState.ByteCount = 0;
44 InternalState.BufferOffset = 0;
45 }
46
47 static uint32_t rol32(uint32_t number, uint8_t bits) {
48 return ((number << bits) | (number >> (32 - bits)));
49 }
50
51 void SHA1::hashBlock() {
52 uint8_t i;
53 uint32_t a, b, c, d, e, t;
54
55 a = InternalState.State[0];
56 b = InternalState.State[1];
57 c = InternalState.State[2];
58 d = InternalState.State[3];
59 e = InternalState.State[4];
60 for (i = 0; i < 80; i++) {
61 if (i >= 16) {
62 t = InternalState.Buffer[(i + 13) & 15] ^
63 InternalState.Buffer[(i + 8) & 15] ^
64 InternalState.Buffer[(i + 2) & 15] ^ InternalState.Buffer[i & 15];
65 InternalState.Buffer[i & 15] = rol32(t, 1);
66 }
67 if (i < 20) {
68 t = (d ^ (b & (c ^ d))) + SHA1_K0;
69 } else if (i < 40) {
70 t = (b ^ c ^ d) + SHA1_K20;
71 } else if (i < 60) {
72 t = ((b & c) | (d & (b | c))) + SHA1_K40;
73 } else {
74 t = (b ^ c ^ d) + SHA1_K60;
75 }
76 t += rol32(a, 5) + e + InternalState.Buffer[i & 15];
77 e = d;
78 d = c;
79 c = rol32(b, 30);
80 b = a;
81 a = t;
82 }
83 InternalState.State[0] += a;
84 InternalState.State[1] += b;
85 InternalState.State[2] += c;
86 InternalState.State[3] += d;
87 InternalState.State[4] += e;
88 }
89
90 void SHA1::addUncounted(uint8_t data) {
91 uint8_t *const b = (uint8_t *)InternalState.Buffer;
92 #ifdef SHA_BIG_ENDIAN
93 b[InternalState.BufferOffset] = data;
94 #else
95 b[InternalState.BufferOffset ^ 3] = data;
96 #endif
97 InternalState.BufferOffset++;
98 if (InternalState.BufferOffset == BLOCK_LENGTH) {
99 hashBlock();
100 InternalState.BufferOffset = 0;
101 }
102 }
103
104 void SHA1::writebyte(uint8_t data) {
105 ++InternalState.ByteCount;
106 addUncounted(data);
107 }
108
109 void SHA1::update(ArrayRef Data) {
110 for (auto &C : Data)
111 writebyte(C);
112 }
113
114 void SHA1::pad() {
115 // Implement SHA-1 padding (fips180-2 ยง5.1.1)
116
117 // Pad with 0x80 followed by 0x00 until the end of the block
118 addUncounted(0x80);
119 while (InternalState.BufferOffset != 56)
120 addUncounted(0x00);
121
122 // Append length in the last 8 bytes
123 addUncounted(0); // We're only using 32 bit lengths
124 addUncounted(0); // But SHA-1 supports 64 bit lengths
125 addUncounted(0); // So zero pad the top bits
126 addUncounted(InternalState.ByteCount >> 29); // Shifting to multiply by 8
127 addUncounted(InternalState.ByteCount >>
128 21); // as SHA-1 supports bitstreams as well as
129 addUncounted(InternalState.ByteCount >> 13); // byte.
130 addUncounted(InternalState.ByteCount >> 5);
131 addUncounted(InternalState.ByteCount << 3);
132 }
133
134 StringRef SHA1::final() {
135 // Pad to complete the last block
136 pad();
137
138 #ifdef SHA_BIG_ENDIAN
139 // Just copy the current state
140 for (int i = 0; i < 5; i++) {
141 HashResult[i] = InternalState.State[i];
142 }
143 #else
144 // Swap byte order back
145 for (int i = 0; i < 5; i++) {
146 HashResult[i] = (((InternalState.State[i]) << 24) & 0xff000000) |
147 (((InternalState.State[i]) << 8) & 0x00ff0000) |
148 (((InternalState.State[i]) >> 8) & 0x0000ff00) |
149 (((InternalState.State[i]) >> 24) & 0x000000ff);
150 }
151 #endif
152
153 // Return pointer to hash (20 characters)
154 return StringRef((char *)HashResult, HASH_LENGTH);
155 }
156
157 StringRef SHA1::result() {
158 auto StateToRestore = InternalState;
159
160 auto Hash = final();
161
162 // Restore the state
163 InternalState = StateToRestore;
164
165 // Return pointer to hash (20 characters)
166 return Hash;
167 }
5151 formatted_raw_ostream_test.cpp
5252 raw_ostream_test.cpp
5353 raw_pwrite_stream_test.cpp
54 raw_sha1_ostream_test.cpp
5455 )
5556
5657 # ManagedStatic.cpp uses .
0 //===- llvm/unittest/Support/raw_ostream_test.cpp - raw_ostream tests -----===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "gtest/gtest.h"
10 #include "llvm/ADT/SmallString.h"
11 #include "llvm/Support/Format.h"
12 #include "llvm/Support/raw_sha1_ostream.h"
13
14 #include
15
16 using namespace llvm;
17
18 static std::string toHex(StringRef Input) {
19 static const char *const LUT = "0123456789ABCDEF";
20 size_t Length = Input.size();
21
22 std::string Output;
23 Output.reserve(2 * Length);
24 for (size_t i = 0; i < Length; ++i) {
25 const unsigned char c = Input[i];
26 Output.push_back(LUT[c >> 4]);
27 Output.push_back(LUT[c & 15]);
28 }
29 return Output;
30 }
31
32 TEST(raw_sha1_ostreamTest, Basic) {
33 llvm::raw_sha1_ostream Sha1Stream;
34 Sha1Stream << "Hello World!";
35 auto Hash = toHex(Sha1Stream.sha1());
36
37 ASSERT_EQ("2EF7BDE608CE5404E97D5F042F95F89F1C232871", Hash);
38 }
39
40 // Check that getting the intermediate hash in the middle of the stream does
41 // not invalidate the final result.
42 TEST(raw_sha1_ostreamTest, Intermediate) {
43 llvm::raw_sha1_ostream Sha1Stream;
44 Sha1Stream << "Hello";
45 auto Hash = toHex(Sha1Stream.sha1());
46
47 ASSERT_EQ("F7FF9E8B7BB2E09B70935A5D785E0CC5D9D0ABF0", Hash);
48 Sha1Stream << " World!";
49 Hash = toHex(Sha1Stream.sha1());
50
51 // Compute the non-split hash separately as a reference.
52 llvm::raw_sha1_ostream NonSplitSha1Stream;
53 NonSplitSha1Stream << "Hello World!";
54 auto NonSplitHash = toHex(NonSplitSha1Stream.sha1());
55
56 ASSERT_EQ(NonSplitHash, Hash);
57 }
58
59 TEST(raw_sha1_ostreamTest, Reset) {
60 llvm::raw_sha1_ostream Sha1Stream;
61 Sha1Stream << "Hello";
62 auto Hash = toHex(Sha1Stream.sha1());
63
64 ASSERT_EQ("F7FF9E8B7BB2E09B70935A5D785E0CC5D9D0ABF0", Hash);
65
66 Sha1Stream.resetHash();
67 Sha1Stream << " World!";
68 Hash = toHex(Sha1Stream.sha1());
69
70 ASSERT_EQ("7447F2A5A42185C8CF91E632789C431830B59067", Hash);
71 }