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
;
47 explicit SHA1(const std::array
<uint8_t, 20>& sha1
) {
48 for (auto i
= 0; i
< kQNumWords
; i
++) {
59 * Build from a SHA1 hexadecimal string
61 explicit SHA1(folly::StringPiece str
) {
62 assertx(str
.size() == kStrLen
);
64 char buf
[kQWordHexLen
+ 1];
65 buf
[kQWordHexLen
] = '\0';
66 for (auto i
= 0; i
< kQNumWords
; i
++) {
67 memcpy(buf
, str
.begin() + (i
* kQWordHexLen
), kQWordHexLen
);
68 q
.at(i
) = strtoul(buf
, nullptr, 16);
72 // Blob is assumed to be in network byte order.
73 explicit SHA1(const void* blob
, DEBUG_ONLY
size_t len
) {
74 assertx(len
== kQNumWords
* kQWordLen
);
76 for (auto i
= 0; i
< kQNumWords
; i
++) {
77 q
.at(i
) = ntohl(reinterpret_cast<const uint32_t*>(blob
)[i
]);
81 explicit SHA1(uint64_t x
): q
{} {
82 q
.at(kQNumWords
- 2) = x
>> 32;
83 q
.at(kQNumWords
- 1) = x
;
86 // Copy out in network byte order.
87 void nbo(void* blob
) const {
88 for (auto i
= 0; i
< kQNumWords
; i
++) {
89 reinterpret_cast<uint32_t*>(blob
)[i
] = htonl(q
.at(i
));
93 std::string
toString() const {
95 char sha1nbo
[kQNumWords
* kQWordLen
];
97 folly::hexlify(folly::StringPiece(sha1nbo
, sizeof sha1nbo
), ret
);
101 // Convert to a string using an arbitrary base-64 alphabet. This
102 // leaves two unused bits (27 base-64 characters is 162 bits), which
103 // can be used to encode extra data.
104 std::string
toStringBase64(unsigned int extra
= 0) const {
105 assertx(extra
< 4); // Only room for two bits
107 static const char table
[64] = {
108 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
109 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
110 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
111 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D',
112 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
113 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
118 char sha1nbo
[kQNumWords
* kQWordLen
];
121 // Below logic is specialized for this size:
122 static_assert(sizeof(sha1nbo
) == 20);
124 for (size_t i
= 0; i
< sizeof(sha1nbo
)-2; i
+= 3) {
125 ret
.push_back(table
[(sha1nbo
[i
] >> 2) & 0x3F]);
126 ret
.push_back(table
[((sha1nbo
[i
] & 0x03) << 4) |
127 ((sha1nbo
[i
+1] & 0xF0) >> 4)]);
128 ret
.push_back(table
[((sha1nbo
[i
+1] & 0x0F) << 2) |
129 ((sha1nbo
[i
+2] & 0xC0) >> 6)]);
130 ret
.push_back(table
[sha1nbo
[i
+2] & 0x3F]);
132 ret
.push_back(table
[(sha1nbo
[sizeof(sha1nbo
)-2] >> 2) & 0x3F]);
133 ret
.push_back(table
[((sha1nbo
[sizeof(sha1nbo
)-2] & 0x03) << 4) |
134 ((sha1nbo
[sizeof(sha1nbo
)-1] & 0xF0) >> 4)]);
135 ret
.push_back(table
[((sha1nbo
[sizeof(sha1nbo
)-1] & 0x0F) << 2) + extra
]);
139 bool operator==(const SHA1
& r
) const {
140 for (auto i
= 0; i
< kQNumWords
; i
++) {
141 if (q
.at(i
) != r
.q
.at(i
)) {
148 bool operator<(const SHA1
& r
) const {
149 for (auto i
= 0; i
< kQNumWords
; i
++) {
150 if (q
.at(i
) < r
.q
.at(i
)) {
154 if (q
.at(i
) > r
.q
.at(i
)) {
161 uint64_t hash() const {
162 // All the bits here are fantastically good.
163 return (uint64_t(q
[0]) << 32) + q
[1];
166 template <typename SerDe
> void serde(SerDe
& serde
) {
167 for (auto& w
: q
) serde(w
);
171 //////////////////////////////////////////////////////////////////////
175 //////////////////////////////////////////////////////////////////////
179 struct hash
<HPHP::SHA1
> {
180 size_t operator()(const HPHP::SHA1
& sha1
) const { return sha1
.hash(); }
184 //////////////////////////////////////////////////////////////////////