hash/include/nil/crypto3/detail/digest.hpp
Go to the documentation of this file.
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2018-2020 Mikhail Komarov <nemo@nil.foundation>
3 // Copyright (c) 2020 Nikita Kaskov <nbering@nil.foundation>
4 //
5 // MIT License
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a copy
8 // of this software and associated documentation files (the "Software"), to deal
9 // in the Software without restriction, including without limitation the rights
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 // copies of the Software, and to permit persons to whom the Software is
12 // furnished to do so, subject to the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included in all
15 // copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 // SOFTWARE.
24 //---------------------------------------------------------------------------//
25 
26 #ifndef CRYPTO3_DIGEST_HPP
27 #define CRYPTO3_DIGEST_HPP
28 
29 #include <iostream>
30 
31 #include <boost/static_assert.hpp>
32 #include <boost/assert.hpp>
33 
34 #include <boost/container/small_vector.hpp>
35 
36 #include <nil/crypto3/detail/pack.hpp>
37 #include <nil/crypto3/detail/octet.hpp>
38 
39 namespace nil {
40  namespace crypto3 {
71  template<std::size_t DigestBits>
72  struct digest : public boost::container::small_vector<octet_type, DigestBits / octet_bits> {
73 
74  digest() : boost::container::small_vector<octet_type, DigestBits / octet_bits>() {};
75 
76  digest(std::size_t sz, octet_type ot) :
77  boost::container::small_vector<octet_type, DigestBits / octet_bits>(sz, ot) {};
78  };
79 
80  // template<std::size_t DigestBits>
81  // using digest = boost::container::small_vector<octet_type, DigestBits / octet_bits>;
82 
83  namespace detail {
84  template<std::size_t DigestBits, typename OutputIterator>
85  OutputIterator to_ascii(const digest<DigestBits> &d, OutputIterator it) {
86  for (std::size_t j = 0; j < d.size(); ++j) {
87  octet_type b = d[j];
88  *it++ = "0123456789abcdef"[(b >> 4) & 0xF];
89  *it++ = "0123456789abcdef"[(b >> 0) & 0xF];
90  }
91  return it;
92  }
93 
94  template<std::size_t DigestBits>
95  digest<DigestBits / 4 + 1> c_str(const digest<DigestBits> &d) {
96  digest<DigestBits / 4 + 1> s;
97  to_ascii<DigestBits>(d, std::back_inserter(s));
98  s.push_back('\0');
99  return s;
100  }
101  } // namespace detail
102 
111  template<unsigned NewBits, unsigned OldBits>
112  digest<NewBits> reserve(const digest<OldBits> &od) {
113  digest<NewBits> nd;
114  unsigned bytes = sizeof(octet_type) * (NewBits < OldBits ? NewBits : OldBits) / octet_bits;
115  std::memcpy(nd.data(), od.data(), bytes);
116  return nd;
117  }
118 
127  template<std::size_t DigestBits>
128  digest<DigestBits> resize(const digest<DigestBits> &od, std::size_t new_size) {
129 
130  std::size_t old_size = od.size();
131 
132  if (new_size == old_size)
133  return od;
134 
135  digest<DigestBits> nd(new_size, octet_type());
136  std::size_t bytes = sizeof(octet_type) * (old_size < new_size ? old_size : new_size);
137  std::memcpy(nd.data(), od.data(), bytes);
138  return nd;
139  }
140 
151  template<unsigned NewBits, unsigned OldBits>
152  digest<NewBits> truncate(const digest<OldBits> &od) {
153  BOOST_STATIC_ASSERT(NewBits <= OldBits);
154  return resize<NewBits>(od);
155  }
156 
157  template<unsigned DB1, unsigned DB2>
158  bool operator==(const digest<DB1> &a, const digest<DB2> &b) {
159  unsigned const DB = DB1 < DB2 ? DB2 : DB1;
160  return resize<DB>(a).base_array() == resize<DB>(b).base_array();
161  }
162 
163  template<unsigned DB1, unsigned DB2>
164  bool operator!=(const digest<DB1> &a, const digest<DB2> &b) {
165  return !(a == b);
166  }
167 
168  template<unsigned DB1, unsigned DB2>
169  bool operator<(const digest<DB1> &a, const digest<DB2> &b) {
170  unsigned const DB = DB1 < DB2 ? DB2 : DB1;
171  return resize<DB>(a).base_array() < resize<DB>(b).base_array();
172  }
173 
174  template<unsigned DB1, unsigned DB2>
175  bool operator>(const digest<DB1> &a, const digest<DB2> &b) {
176  return b < a;
177  }
178 
179  template<unsigned DB1, unsigned DB2>
180  bool operator<=(const digest<DB1> &a, const digest<DB2> &b) {
181  return !(b < a);
182  }
183 
184  template<unsigned DB1, unsigned DB2>
185  bool operator>=(const digest<DB1> &a, const digest<DB2> &b) {
186  return !(b > a);
187  }
188 
189  template<unsigned DB>
190  bool operator!=(digest<DB> const &a, char const *b) {
191  BOOST_ASSERT(std::strlen(b) == DB / 4);
192  return static_cast<bool>(std::strcmp(a.cstring().data(), b));
193  }
194 
195  template<unsigned DB>
196  bool operator==(digest<DB> const &a, char const *b) {
197  return !(a != b);
198  }
199 
200  template<unsigned DB>
201  bool operator!=(char const *b, digest<DB> const &a) {
202  return a != b;
203  }
204 
205  template<unsigned DB>
206  bool operator==(char const *b, digest<DB> const &a) {
207  return a == b;
208  }
209 
210  template<unsigned DB>
211  std::ostream &operator<<(std::ostream &sink, digest<DB> const &d) {
212  d.to_ascii(std::ostream_iterator<char>(sink));
213  return sink;
214  }
215 
216  template<unsigned DB>
217  std::istream &operator>>(std::istream &source, digest<DB> &d) {
218  std::array<char, DB / 4> a = {{}};
219  for (unsigned i = 0; i < a.size(); ++i) {
220  char c;
221  if (!source.get(c)) {
222  source.setstate(std::ios::failbit);
223  break;
224  }
225  if (!std::isxdigit(c, source.getloc())) {
226  source.unget();
227  source.setstate(std::ios::failbit);
228  break;
229  }
230 
231  if (std::isdigit(c, source.getloc())) {
232  a[i] = (c - '0');
233  } else {
234  a[i] = std::toupper(c, source.getloc()) - 'A' + 0xA;
235  }
236  }
237  detail::pack<stream_endian::big_bit, stream_endian::big_bit, 4, 8>(a.begin(), a.end(), d.begin());
238  return source;
239  }
240  } // namespace crypto3
241 } // namespace nil
242 
243 namespace std {
244  template<std::size_t DigestBits>
245  std::string to_string(const nil::crypto3::digest<DigestBits> &d) {
246  nil::crypto3::digest<DigestBits / 4 + 1> cstr = nil::crypto3::detail::c_str(d);
247  return std::string(cstr.begin(), cstr.begin() + cstr.size() - 1);
248  }
249 } // namespace std
250 
251 #endif // CRYPTO3_DIGEST_HPP
std::string to_string(const nil::crypto3::digest< DigestBits > &d)
Definition: block/include/nil/crypto3/detail/digest.hpp:248
OutputIterator to_ascii(const digest< DigestBits > &d, OutputIterator it)
Definition: block/include/nil/crypto3/detail/digest.hpp:86
digest< DigestBits/4+1 > c_str(const digest< DigestBits > &d)
Definition: block/include/nil/crypto3/detail/digest.hpp:98
boost::uint_t< octet_bits >::least octet_type
Definition: algebra/include/nil/crypto3/detail/octet.hpp:33
std::istream & operator>>(std::istream &source, digest< DB > &d)
Definition: block/include/nil/crypto3/detail/digest.hpp:220
bool operator>(const digest< DB1 > &a, const digest< DB2 > &b)
Definition: block/include/nil/crypto3/detail/digest.hpp:178
bool operator<(const digest< DB1 > &a, const digest< DB2 > &b)
Definition: block/include/nil/crypto3/detail/digest.hpp:172
bool operator!=(const secure_allocator< T > &, const secure_allocator< U > &)
Definition: secure_allocator.hpp:98
std::ostream & operator<<(std::ostream &sink, digest< DB > const &d)
Definition: block/include/nil/crypto3/detail/digest.hpp:214
bool operator==(const secure_allocator< T > &, const secure_allocator< U > &)
Definition: secure_allocator.hpp:93
digest< DigestBits > resize(const digest< DigestBits > &od, std::size_t new_size)
Definition: block/include/nil/crypto3/detail/digest.hpp:131
boost::container::small_vector< octet_type, DigestBits/octet_bits > digest
Definition: codec/include/nil/crypto3/detail/digest.hpp:71
digest< NewBits > truncate(const digest< OldBits > &od)
Definition: block/include/nil/crypto3/detail/digest.hpp:155
bool operator<=(const digest< DB1 > &a, const digest< DB2 > &b)
Definition: block/include/nil/crypto3/detail/digest.hpp:183
digest< NewBits > reserve(const digest< OldBits > &od)
Definition: block/include/nil/crypto3/detail/digest.hpp:115
bool operator>=(const digest< DB1 > &a, const digest< DB2 > &b)
Definition: block/include/nil/crypto3/detail/digest.hpp:188
Definition: pair.hpp:31
Definition: block/include/nil/crypto3/detail/digest.hpp:72
digest()
Definition: hash/include/nil/crypto3/detail/digest.hpp:74
digest(std::size_t sz, octet_type ot)
Definition: hash/include/nil/crypto3/detail/digest.hpp:76