aboutsummaryrefslogtreecommitdiff
path: root/include/salticidae/stream.h
diff options
context:
space:
mode:
authorDeterminant <ted.sybil@gmail.com>2018-06-26 12:58:54 -0400
committerDeterminant <ted.sybil@gmail.com>2018-06-26 12:58:54 -0400
commit5c3b39340d365f5ff37a79424956591e87b44816 (patch)
tree45fc59c19ed95c44bacbbe59396d8bc1b25872dd /include/salticidae/stream.h
init
Diffstat (limited to 'include/salticidae/stream.h')
-rw-r--r--include/salticidae/stream.h274
1 files changed, 274 insertions, 0 deletions
diff --git a/include/salticidae/stream.h b/include/salticidae/stream.h
new file mode 100644
index 0000000..4259773
--- /dev/null
+++ b/include/salticidae/stream.h
@@ -0,0 +1,274 @@
+/**
+ * Copyright (c) 2018 Cornell University.
+ *
+ * Author: Ted Yin <tederminant@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _SALTICIDAE_STREAM_H
+#define _SALTICIDAE_STREAM_H
+
+#include "salticidae/type.h"
+#include "salticidae/crypto.h"
+
+namespace salticidae {
+
+template<size_t N, typename T> class Blob;
+using uint256_t = Blob<256, uint64_t>;
+
+class DataStream {
+ bytearray_t buffer;
+ size_t offset;
+
+ public:
+ DataStream(): offset(0) {}
+ DataStream(const uint8_t *begin, const uint8_t *end): buffer(begin, end), offset(0) {}
+ DataStream(bytearray_t &&data): buffer(std::move(data)), offset(0) {}
+ DataStream(const bytearray_t &data): buffer(data), offset(0) {}
+
+ DataStream(DataStream &&other):
+ buffer(std::move(other.buffer)),
+ offset(other.offset) {}
+
+ DataStream(const DataStream &other):
+ buffer(other.buffer),
+ offset(other.offset) {}
+
+ DataStream &operator=(const DataStream &other) {
+ buffer = other.buffer;
+ offset = other.offset;
+ return *this;
+ }
+
+ DataStream &operator=(DataStream &&other) {
+ buffer = std::move(other.buffer);
+ offset = std::move(other.offset);
+ return *this;
+ }
+
+ uint8_t *data() { return &buffer[offset]; }
+
+ void clear() {
+ buffer.clear();
+ offset = 0;
+ }
+
+ size_t size() const {
+ return buffer.size() - offset;
+ }
+
+ template<typename T>
+ typename std::enable_if<std::is_integral<T>::value, DataStream &>::type
+ operator<<(T d) {
+ buffer.resize(buffer.size() + sizeof(T));
+ *(reinterpret_cast<T *>(&*buffer.end() - sizeof(T))) = d;
+ return *this;
+ }
+
+ template<typename T>
+ typename std::enable_if<is_ranged<T>::value, DataStream &>::type
+ operator<<(const T &d) {
+ buffer.insert(buffer.end(), d.begin(), d.end());
+ return *this;
+ }
+
+ void put_data(uint8_t *begin, uint8_t *end) {
+ size_t len = end - begin;
+ buffer.resize(buffer.size() + len);
+ memmove(&*buffer.end() - len, begin, len);
+ }
+
+ template<typename T>
+ typename std::enable_if<!is_ranged<T>::value &&
+ !std::is_integral<T>::value, DataStream &>::type
+ operator<<(const T &obj) {
+ obj.serialize(*this);
+ return *this;
+ }
+
+ DataStream &operator<<(const char *cstr) {
+ put_data((uint8_t *)cstr, (uint8_t *)cstr + strlen(cstr));
+ return *this;
+ }
+
+ template<typename T>
+ typename std::enable_if<std::is_integral<T>::value, DataStream &>::type
+ operator>>(T &d) {
+#ifndef SALTICIDAE_NOCHECK
+ if (offset >= buffer.size())
+ throw std::ios_base::failure("insufficient buffer");
+#endif
+ d = *(reinterpret_cast<T *>(&buffer[offset]));
+ offset += sizeof(T);
+ return *this;
+ }
+
+ template<typename T>
+ typename std::enable_if<!std::is_integral<T>::value, DataStream &>::type
+ operator>>(T &obj) {
+ obj.unserialize(*this);
+ return *this;
+ }
+
+ std::string get_hex() const {
+ char buf[3];
+ DataStream s;
+ for (auto it = buffer.begin() + offset; it != buffer.end(); it++)
+ {
+ sprintf(buf, "%02x", *it);
+ s.put_data((uint8_t *)buf, (uint8_t *)buf + 2);
+ }
+ return std::string(s.buffer.begin(), s.buffer.end());
+ }
+
+ void load_hex(const std::string &hexstr) {
+ size_t len = hexstr.size();
+ const char *p;
+ uint8_t *bp;
+ unsigned int tmp;
+ if (len & 1)
+ throw std::runtime_error("not a valid hex string");
+ buffer.resize(len >> 1);
+ offset = 0;
+ for (p = hexstr.data(), bp = &*buffer.begin();
+ p < hexstr.data() + len; p += 2, bp++)
+ {
+ if (sscanf(p, "%02x", &tmp) != 1)
+ throw std::runtime_error("not a valid hex string");
+ *bp = tmp;
+ }
+ }
+
+ operator bytearray_t () const & {
+ return bytearray_t(buffer.begin() + offset, buffer.end());
+ }
+
+ operator bytearray_t () const && {
+ return std::move(buffer);
+ }
+
+ operator std::string () const & {
+ return std::string(buffer.begin() + offset, buffer.end());
+ }
+
+ inline uint256_t get_hash() const;
+};
+
+template<size_t N, typename T = uint64_t>
+class Blob {
+ using _impl_type = T;
+ static const size_t bit_per_datum = sizeof(_impl_type) * 8;
+ static_assert(!(N % bit_per_datum), "N must be divisible by bit_per_datum");
+ static const auto _len = N / bit_per_datum;
+ _impl_type data[_len];
+ bool loaded;
+
+ public:
+
+ Blob(): loaded(false) {}
+ Blob(const bytearray_t &arr) {
+ if (arr.size() != N / 8)
+ throw std::runtime_error("incorrect Blob size");
+ load(&*arr.begin());
+ }
+
+ Blob(const uint8_t *arr) { load(arr); }
+
+ void load(const uint8_t *arr) {
+ arr += N / 8;
+ for (_impl_type *ptr = data + _len; ptr > data;)
+ {
+ _impl_type x = 0;
+ for (unsigned j = 0; j < sizeof(_impl_type); j++)
+ x = (x << 8) | *(--arr);
+ *(--ptr) = x;
+ }
+ loaded = true;
+ }
+
+ bool is_null() const { return !loaded; }
+
+ bool operator==(const Blob<N> &other) const {
+ for (size_t i = 0; i < _len; i++)
+ if (data[i] != other.data[i])
+ return false;
+ return true;
+ }
+
+ bool operator!=(const Blob<N> &other) const {
+ return !(data == other);
+ }
+
+ size_t cheap_hash() const { return *data; }
+
+ void serialize(DataStream &s) const {
+ for (const _impl_type *ptr = data; ptr < data + _len; ptr++)
+ s << htole(*ptr);
+ }
+
+ void unserialize(DataStream &s) {
+ for (_impl_type *ptr = data; ptr < data + _len; ptr++)
+ {
+ _impl_type x;
+ s >> x;
+ *ptr = letoh(x);
+ }
+ }
+};
+
+const size_t ENT_HASH_LENGTH = 256 / 8;
+
+uint256_t DataStream::get_hash() const {
+ class SHA256 d;
+ d.update(buffer.begin() + offset, size());
+ return d.digest();
+}
+
+template<typename T> inline uint256_t get_hash(const T &x) {
+ DataStream s;
+ s << x;
+ return s.get_hash();
+}
+
+template<typename T> inline std::string get_hex(const T &x) {
+ DataStream s;
+ s << x;
+ return s.get_hex();
+}
+
+}
+
+namespace std {
+ template <>
+ struct hash<salticidae::uint256_t> {
+ size_t operator()(const salticidae::uint256_t &k) const {
+ return (size_t)k.cheap_hash();
+ }
+ };
+
+ template <>
+ struct hash<const salticidae::uint256_t> {
+ size_t operator()(const salticidae::uint256_t &k) const {
+ return (size_t)k.cheap_hash();
+ }
+ };
+}
+
+#endif