llvm.org GIT mirror llvm / 696fe52
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. From: Mehdi Amini <mehdi.amini@apple.com> git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@265094 91177308-0d34-0410-b5e6-96231b3b80d8 Mehdi Amini 3 years ago
6 changed file(s) with 361 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 static constexpr int BLOCK_LENGTH = 64;
50 static constexpr int HASH_LENGTH = 20;
51
52 // Internal State
53 struct {
54 uint32_t Buffer[BLOCK_LENGTH / 4];
55 uint32_t State[HASH_LENGTH / 4];
56 uint32_t ByteCount;
57 uint8_t BufferOffset;
58 } InternalState;
59
60 // Internal copy of the hash, populated and accessed on calls to result()
61 uint32_t HashResult[HASH_LENGTH / 4];
62
63 // Helper
64 void writebyte(uint8_t data);
65 void hashBlock();
66 void addUncounted(uint8_t data);
67 void pad();
68 };
69
70 } // end llvm namespace
71
72 #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 }