declare_folded_class NO LONGER _in_file
[hiphop-php.git] / hphp / util / sha1.h
blob7a51f98bee8bd4a2c47d815c9ebe686b913f8be1
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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 +----------------------------------------------------------------------+
17 #pragma once
19 #include <array>
20 #include <cstdlib>
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"
30 namespace HPHP {
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;
45 SHA1() : q{} {}
47 explicit SHA1(const std::array<uint8_t, 20>& sha1) {
48 for (auto i = 0; i < kQNumWords; i++) {
49 uint32_t u =
50 (sha1[i*4] << 24) +
51 (sha1[i*4+1] << 16) +
52 (sha1[i*4+2] << 8) +
53 sha1[i*4+3];
54 q.at(i) = u;
58 /**
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 {
94 std::string ret;
95 char sha1nbo[kQNumWords * kQWordLen];
96 nbo(sha1nbo);
97 folly::hexlify(folly::StringPiece(sha1nbo, sizeof sha1nbo), ret);
98 return 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',
114 'Y', 'Z', '_', '+'
117 std::string ret;
118 char sha1nbo[kQNumWords * kQWordLen];
119 nbo(sha1nbo);
121 // Below logic is specialized for this size:
122 static_assert(sizeof(sha1nbo) == 20);
123 ret.reserve(27);
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]);
136 return ret;
139 bool operator==(const SHA1& r) const {
140 for (auto i = 0; i < kQNumWords; i++) {
141 if (q.at(i) != r.q.at(i)) {
142 return false;
145 return true;
148 bool operator<(const SHA1& r) const {
149 for (auto i = 0; i < kQNumWords; i++) {
150 if (q.at(i) < r.q.at(i)) {
151 return true;
154 if (q.at(i) > r.q.at(i)) {
155 return false;
158 return false;
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 //////////////////////////////////////////////////////////////////////
177 namespace std {
178 template<>
179 struct hash<HPHP::SHA1> {
180 size_t operator()(const HPHP::SHA1& sha1) const { return sha1.hash(); }
184 //////////////////////////////////////////////////////////////////////