2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
22 #include <boost/operators.hpp>
24 #include <folly/Range.h>
25 #include <folly/String.h>
27 #include "hphp/util/assertions.h"
28 #include "hphp/util/byte-order.h"
32 //////////////////////////////////////////////////////////////////////
34 struct SHA1
: private boost::totally_ordered
<SHA1
> {
35 static constexpr size_t kQNumWords
= 5;
36 static constexpr size_t kQWordLen
= sizeof(uint32_t);
38 // One byte = two ascii hex characters
39 static constexpr size_t kQWordHexLen
= 2 * kQWordLen
;
41 static constexpr size_t kStrLen
= kQNumWords
* kQWordHexLen
;
43 std::array
<uint32_t, kQNumWords
> q
;
48 * Build from a SHA1 hexadecimal string
50 explicit SHA1(folly::StringPiece str
) {
51 assertx(str
.size() == kStrLen
);
53 char buf
[kQWordHexLen
+ 1];
54 buf
[kQWordHexLen
] = '\0';
55 for (auto i
= 0; i
< kQNumWords
; i
++) {
56 memcpy(buf
, str
.begin() + (i
* kQWordHexLen
), kQWordHexLen
);
57 q
.at(i
) = strtoul(buf
, nullptr, 16);
61 // Blob is assumed to be in network byte order.
62 explicit SHA1(const void* blob
, DEBUG_ONLY
size_t len
) {
63 assertx(len
== kQNumWords
* kQWordLen
);
65 for (auto i
= 0; i
< kQNumWords
; i
++) {
66 q
.at(i
) = ntohl(reinterpret_cast<const uint32_t*>(blob
)[i
]);
70 explicit SHA1(uint64_t x
): q
{} {
71 q
.at(kQNumWords
- 2) = x
>> 32;
72 q
.at(kQNumWords
- 1) = x
;
75 // Copy out in network byte order.
76 void nbo(void* blob
) const {
77 for (auto i
= 0; i
< kQNumWords
; i
++) {
78 reinterpret_cast<uint32_t*>(blob
)[i
] = htonl(q
.at(i
));
82 std::string
toString() const {
84 char sha1nbo
[kQNumWords
* kQWordLen
];
86 folly::hexlify(folly::StringPiece(sha1nbo
, sizeof sha1nbo
), ret
);
90 // Convert to a string using an arbitrary base-64 alphabet. This
91 // leaves two unused bits (27 base-64 characters is 162 bits), which
92 // can be used to encode extra data.
93 std::string
toStringBase64(unsigned int extra
= 0) const {
94 assertx(extra
< 4); // Only room for two bits
96 static const char table
[64] = {
97 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
98 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
99 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
100 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D',
101 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
102 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
107 char sha1nbo
[kQNumWords
* kQWordLen
];
110 // Below logic is specialized for this size:
111 static_assert(sizeof(sha1nbo
) == 20);
113 for (size_t i
= 0; i
< sizeof(sha1nbo
)-2; i
+= 3) {
114 ret
.push_back(table
[(sha1nbo
[i
] >> 2) & 0x3F]);
115 ret
.push_back(table
[((sha1nbo
[i
] & 0x03) << 4) |
116 ((sha1nbo
[i
+1] & 0xF0) >> 4)]);
117 ret
.push_back(table
[((sha1nbo
[i
+1] & 0x0F) << 2) |
118 ((sha1nbo
[i
+2] & 0xC0) >> 6)]);
119 ret
.push_back(table
[sha1nbo
[i
+2] & 0x3F]);
121 ret
.push_back(table
[(sha1nbo
[sizeof(sha1nbo
)-2] >> 2) & 0x3F]);
122 ret
.push_back(table
[((sha1nbo
[sizeof(sha1nbo
)-2] & 0x03) << 4) |
123 ((sha1nbo
[sizeof(sha1nbo
)-1] & 0xF0) >> 4)]);
124 ret
.push_back(table
[((sha1nbo
[sizeof(sha1nbo
)-1] & 0x0F) << 2) + extra
]);
128 bool operator==(const SHA1
& r
) const {
129 for (auto i
= 0; i
< kQNumWords
; i
++) {
130 if (q
.at(i
) != r
.q
.at(i
)) {
137 bool operator<(const SHA1
& r
) const {
138 for (auto i
= 0; i
< kQNumWords
; i
++) {
139 if (q
.at(i
) < r
.q
.at(i
)) {
143 if (q
.at(i
) > r
.q
.at(i
)) {
150 uint64_t hash() const {
151 // All the bits here are fantastically good.
152 return (uint64_t(q
[0]) << 32) + q
[1];
155 template <typename SerDe
> void serde(SerDe
& serde
) {
156 for (auto& w
: q
) serde(w
);
160 //////////////////////////////////////////////////////////////////////
164 //////////////////////////////////////////////////////////////////////
168 struct hash
<HPHP::SHA1
> {
169 size_t operator()(const HPHP::SHA1
& sha1
) const { return sha1
.hash(); }
173 //////////////////////////////////////////////////////////////////////