Zeth - Zerocash on Ethereum  0.8
Reference implementation of the Zeth protocol by Clearmatics
bits.tcc
Go to the documentation of this file.
1 // Copyright (c) 2015-2022 Clearmatics Technologies Ltd
2 //
3 // SPDX-License-Identifier: LGPL-3.0+
4 
5 #ifndef __ZETH_CORE_BITS_TCC__
6 #define __ZETH_CORE_BITS_TCC__
7 
8 #include "libzeth/core/bits.hpp"
9 
10 #include <limits>
11 #include <utility>
12 
13 namespace libzeth
14 {
15 
16 uint8_t char_to_nibble(char);
17 
18 namespace
19 {
20 
21 template<size_t Size>
22 std::vector<bool> array_to_vector(const std::array<bool, Size> &arr)
23 {
24  std::vector<bool> vect(Size);
25  std::copy(arr.begin(), arr.end(), vect.begin());
26  return vect;
27 }
28 
29 } // namespace
30 
31 template<size_t numBits> bits<numBits>::bits()
32 {
33  for (size_t i = 0; i < numBits; ++i) {
34  (*this)[i] = false;
35  }
36 }
37 
38 template<size_t numBits>
39 template<typename... boolList>
40 bits<numBits>::bits(const boolList &...bits)
41  : std::array<bool, numBits>{std::forward<bool>(bits)...}
42 {
43 }
44 
45 template<size_t numBits> std::vector<bool> bits<numBits>::to_vector() const
46 {
47  return array_to_vector(*this);
48 }
49 
50 template<size_t numBits>
51 bits<numBits> bits<numBits>::from_vector(const std::vector<bool> &bin)
52 {
53  if (bin.size() != numBits) {
54  throw std::invalid_argument("invalid vector size");
55  }
56  return bits(bin.begin());
57 }
58 
59 template<size_t numBits>
60 bits<numBits> bits<numBits>::from_hex(const std::string &hex)
61 {
62  if (hex.size() != numBits / 4) {
63  throw std::invalid_argument("invalid hex string length");
64  }
65  bits<numBits> result;
66  size_t i = 0;
67  for (const char c : hex) {
68  const uint8_t nibble = char_to_nibble(c);
69  result[i++] = (nibble & 8) != 0;
70  result[i++] = (nibble & 4) != 0;
71  result[i++] = (nibble & 2) != 0;
72  result[i++] = (nibble & 1) != 0;
73  }
74 
75  return result;
76 }
77 
78 template<size_t numBits>
79 bits<numBits> bits<numBits>::from_size_t(size_t address)
80 {
81  // cppcheck-suppress shiftTooManyBits
82  // cppcheck-suppress knownConditionTrueFalse
83  if ((numBits < 64) && (address >= (1ull << numBits))) {
84  throw std::invalid_argument("Address overflow");
85  }
86 
87  // Initialize one bit at a time, earlying out if address turns to 0. Set
88  // all remaining bits to 0.
89  bool result[numBits];
90  size_t i;
91  for (i = 0; i < numBits && address != 0; ++i, address >>= 1) {
92  result[i] = address & 0x1;
93  }
94  for (; i < numBits; ++i) {
95  result[i] = 0;
96  }
97 
98  return bits_addr<numBits>(result);
99 }
100 
101 template<size_t numBits> bool bits<numBits>::is_zero() const
102 {
103  return !std::any_of(
104  this->begin(), this->end(), [](const bool b) { return b != 0; });
105 };
106 
107 template<size_t numBits>
108 template<typename FieldT>
109 void bits<numBits>::fill_pb_variable_array(
110  libsnark::protoboard<FieldT> &pb,
111  libsnark::pb_variable_array<FieldT> &var_array) const
112 {
113  if (var_array.size() != numBits) {
114  throw std::invalid_argument("invalid pb_variable_array size");
115  }
116  for (size_t i = 0; i < numBits; ++i) {
117  pb.val(var_array[i]) = ((*this)[i]) ? FieldT::one() : FieldT::zero();
118  }
119 }
120 
121 template<size_t numBits>
122 template<typename boolIt>
123 bits<numBits>::bits(boolIt it)
124 {
125  fill_from_iterator(it);
126 }
127 
128 template<size_t numBits>
129 template<typename boolIt>
130 void bits<numBits>::fill_from_iterator(boolIt it)
131 {
132  // (Internal function) Caller expected to check that enough elements are
133  // present before passing an iterator in.
134  for (size_t i = 0; i < numBits; ++i, ++it) {
135  (*this)[i] = *it;
136  }
137 }
138 
139 template<size_t numBits>
140 bits<numBits> bits_xor(const bits<numBits> &a, const bits<numBits> &b)
141 {
142  bits<numBits> result;
143  for (size_t i = 0; i < numBits; ++i) {
144  result[i] = a[i] ^ b[i];
145  }
146  return result;
147 }
148 
149 template<size_t numBits>
150 bits<numBits> bits_add(
151  const bits<numBits> &as, const bits<numBits> &bs, bool with_carry)
152 {
153  bits<numBits> result;
154 
155  bool carry = false;
156  size_t i = numBits;
157  while (i > 0) {
158  --i;
159  // (r, carry) = a + carry,
160  // (result[i], carry) = r + b
161  const bool a = as[i];
162  const bool b = bs[i];
163  bool r = a ^ carry;
164  carry = carry && a;
165  result[i] = r ^ b;
166  carry = carry || (r && b);
167  }
168 
169  // If we ask for the last carry to be taken into account
170  // (with_carry=true) and that the last carry is 1, then we raise an
171  // overflow error
172  if (with_carry && carry) {
173  throw std::overflow_error("Overflow: The sum of the binary addition "
174  "cannot be encoded on <BitLen> bits");
175  }
176 
177  return result;
178 }
179 
180 } // namespace libzeth
181 
182 #endif // __ZETH_CORE_BITS_TCC__