Squashed 'src/snark/' content from commit 9ada3f8
git-subtree-dir: src/snark git-subtree-split: 9ada3f84ab484c57b2247c2f41091fd6a0916573
This commit is contained in:
12
src/common/assert_except.hpp
Normal file
12
src/common/assert_except.hpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef ASSERT_except_H
|
||||
#define ASSERT_except_H
|
||||
|
||||
#include <exception>
|
||||
|
||||
inline void assert_except(bool condition) {
|
||||
if (!condition) {
|
||||
throw std::runtime_error("Assertion failed.");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
74
src/common/data_structures/accumulation_vector.hpp
Normal file
74
src/common/data_structures/accumulation_vector.hpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
|
||||
Declaration of interfaces for an accumulation vector.
|
||||
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef ACCUMULATION_VECTOR_HPP_
|
||||
#define ACCUMULATION_VECTOR_HPP_
|
||||
|
||||
#include "common/data_structures/sparse_vector.hpp"
|
||||
|
||||
namespace libsnark {
|
||||
|
||||
template<typename T>
|
||||
class accumulation_vector;
|
||||
|
||||
template<typename T>
|
||||
std::ostream& operator<<(std::ostream &out, const accumulation_vector<T> &v);
|
||||
|
||||
template<typename T>
|
||||
std::istream& operator>>(std::istream &in, accumulation_vector<T> &v);
|
||||
|
||||
/**
|
||||
* An accumulation vector comprises an accumulation value and a sparse vector.
|
||||
* The method "accumulate_chunk" allows one to accumlate portions of the sparse
|
||||
* vector into the accumualation value.
|
||||
*/
|
||||
template<typename T>
|
||||
class accumulation_vector {
|
||||
public:
|
||||
T first;
|
||||
sparse_vector<T> rest;
|
||||
|
||||
accumulation_vector() = default;
|
||||
accumulation_vector(const accumulation_vector<T> &other) = default;
|
||||
accumulation_vector(accumulation_vector<T> &&other) = default;
|
||||
accumulation_vector(T &&first, sparse_vector<T> &&rest) : first(std::move(first)), rest(std::move(rest)) {};
|
||||
accumulation_vector(T &&first, std::vector<T> &&v) : first(std::move(first)), rest(std::move(v)) {}
|
||||
accumulation_vector(std::vector<T> &&v) : first(T::zero()), rest(std::move(v)) {};
|
||||
|
||||
accumulation_vector<T>& operator=(const accumulation_vector<T> &other) = default;
|
||||
accumulation_vector<T>& operator=(accumulation_vector<T> &&other) = default;
|
||||
|
||||
bool operator==(const accumulation_vector<T> &other) const;
|
||||
|
||||
bool is_fully_accumulated() const;
|
||||
|
||||
size_t domain_size() const;
|
||||
size_t size() const;
|
||||
size_t size_in_bits() const;
|
||||
|
||||
template<typename FieldT>
|
||||
accumulation_vector<T> accumulate_chunk(const typename std::vector<FieldT>::const_iterator &it_begin,
|
||||
const typename std::vector<FieldT>::const_iterator &it_end,
|
||||
const size_t offset) const;
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
std::ostream& operator<<(std::ostream &out, const accumulation_vector<T> &v);
|
||||
|
||||
template<typename T>
|
||||
std::istream& operator>>(std::istream &in, accumulation_vector<T> &v);
|
||||
|
||||
} // libsnark
|
||||
|
||||
#include "common/data_structures/accumulation_vector.tcc"
|
||||
|
||||
#endif // ACCUMULATION_VECTOR_HPP_
|
||||
84
src/common/data_structures/accumulation_vector.tcc
Normal file
84
src/common/data_structures/accumulation_vector.tcc
Normal file
@@ -0,0 +1,84 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
|
||||
Implementation of interfaces for an accumulation vector.
|
||||
|
||||
See accumulation_vector.hpp .
|
||||
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef ACCUMULATION_VECTOR_TCC_
|
||||
#define ACCUMULATION_VECTOR_TCC_
|
||||
|
||||
namespace libsnark {
|
||||
|
||||
template<typename T>
|
||||
bool accumulation_vector<T>::operator==(const accumulation_vector<T> &other) const
|
||||
{
|
||||
return (this->first == other.first && this->rest == other.rest);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool accumulation_vector<T>::is_fully_accumulated() const
|
||||
{
|
||||
return rest.empty();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
size_t accumulation_vector<T>::domain_size() const
|
||||
{
|
||||
return rest.domain_size();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
size_t accumulation_vector<T>::size() const
|
||||
{
|
||||
return rest.domain_size();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
size_t accumulation_vector<T>::size_in_bits() const
|
||||
{
|
||||
const size_t first_size_in_bits = T::size_in_bits();
|
||||
const size_t rest_size_in_bits = rest.size_in_bits();
|
||||
return first_size_in_bits + rest_size_in_bits;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename FieldT>
|
||||
accumulation_vector<T> accumulation_vector<T>::accumulate_chunk(const typename std::vector<FieldT>::const_iterator &it_begin,
|
||||
const typename std::vector<FieldT>::const_iterator &it_end,
|
||||
const size_t offset) const
|
||||
{
|
||||
std::pair<T, sparse_vector<T> > acc_result = rest.template accumulate<FieldT>(it_begin, it_end, offset);
|
||||
T new_first = first + acc_result.first;
|
||||
return accumulation_vector<T>(std::move(new_first), std::move(acc_result.second));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::ostream& operator<<(std::ostream& out, const accumulation_vector<T> &v)
|
||||
{
|
||||
out << v.first << OUTPUT_NEWLINE;
|
||||
out << v.rest << OUTPUT_NEWLINE;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::istream& operator>>(std::istream& in, accumulation_vector<T> &v)
|
||||
{
|
||||
in >> v.first;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
in >> v.rest;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
} // libsnark
|
||||
|
||||
#endif // ACCUMULATION_VECTOR_TCC_
|
||||
71
src/common/data_structures/merkle_tree.hpp
Normal file
71
src/common/data_structures/merkle_tree.hpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
|
||||
Declaration of interfaces for a Merkle tree.
|
||||
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef MERKLE_TREE_HPP_
|
||||
#define MERKLE_TREE_HPP_
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "common/utils.hpp"
|
||||
|
||||
namespace libsnark {
|
||||
|
||||
/**
|
||||
* A Merkle tree is maintained as two maps:
|
||||
* - a map from addresses to values, and
|
||||
* - a map from addresses to hashes.
|
||||
*
|
||||
* The second map maintains the intermediate hashes of a Merkle tree
|
||||
* built atop the values currently stored in the tree (the
|
||||
* implementation admits a very efficient support for sparse
|
||||
* trees). Besides offering methods to load and store values, the
|
||||
* class offers methods to retrieve the root of the Merkle tree and to
|
||||
* obtain the authentication paths for (the value at) a given address.
|
||||
*/
|
||||
|
||||
typedef bit_vector merkle_authentication_node;
|
||||
typedef std::vector<merkle_authentication_node> merkle_authentication_path;
|
||||
|
||||
template<typename HashT>
|
||||
class merkle_tree {
|
||||
private:
|
||||
|
||||
typedef typename HashT::hash_value_type hash_value_type;
|
||||
typedef typename HashT::merkle_authentication_path_type merkle_authentication_path_type;
|
||||
|
||||
public:
|
||||
|
||||
std::vector<hash_value_type> hash_defaults;
|
||||
std::map<size_t, bit_vector> values;
|
||||
std::map<size_t, hash_value_type> hashes;
|
||||
|
||||
size_t depth;
|
||||
size_t value_size;
|
||||
size_t digest_size;
|
||||
|
||||
merkle_tree(const size_t depth, const size_t value_size);
|
||||
merkle_tree(const size_t depth, const size_t value_size, const std::vector<bit_vector> &contents_as_vector);
|
||||
merkle_tree(const size_t depth, const size_t value_size, const std::map<size_t, bit_vector> &contents);
|
||||
|
||||
bit_vector get_value(const size_t address) const;
|
||||
void set_value(const size_t address, const bit_vector &value);
|
||||
|
||||
hash_value_type get_root() const;
|
||||
merkle_authentication_path_type get_path(const size_t address) const;
|
||||
|
||||
void dump() const;
|
||||
};
|
||||
|
||||
} // libsnark
|
||||
|
||||
#include "common/data_structures/merkle_tree.tcc"
|
||||
|
||||
#endif // MERKLE_TREE_HPP_
|
||||
246
src/common/data_structures/merkle_tree.tcc
Normal file
246
src/common/data_structures/merkle_tree.tcc
Normal file
@@ -0,0 +1,246 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
|
||||
Implementation of interfaces for Merkle tree.
|
||||
|
||||
See merkle_tree.hpp .
|
||||
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef MERKLE_TREE_TCC
|
||||
#define MERKLE_TREE_TCC
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common/profiling.hpp"
|
||||
#include "common/utils.hpp"
|
||||
|
||||
namespace libsnark {
|
||||
|
||||
template<typename HashT>
|
||||
typename HashT::hash_value_type two_to_one_CRH(const typename HashT::hash_value_type &l,
|
||||
const typename HashT::hash_value_type &r)
|
||||
{
|
||||
typename HashT::hash_value_type new_input;
|
||||
new_input.insert(new_input.end(), l.begin(), l.end());
|
||||
new_input.insert(new_input.end(), r.begin(), r.end());
|
||||
|
||||
const size_t digest_size = HashT::get_digest_len();
|
||||
assert(l.size() == digest_size);
|
||||
assert(r.size() == digest_size);
|
||||
|
||||
return HashT::get_hash(new_input);
|
||||
}
|
||||
|
||||
template<typename HashT>
|
||||
merkle_tree<HashT>::merkle_tree(const size_t depth, const size_t value_size) :
|
||||
depth(depth), value_size(value_size)
|
||||
{
|
||||
assert(depth < sizeof(size_t) * 8);
|
||||
|
||||
digest_size = HashT::get_digest_len();
|
||||
assert(value_size <= digest_size);
|
||||
|
||||
hash_value_type last(digest_size);
|
||||
hash_defaults.reserve(depth+1);
|
||||
hash_defaults.emplace_back(last);
|
||||
for (size_t i = 0; i < depth; ++i)
|
||||
{
|
||||
last = two_to_one_CRH<HashT>(last, last);
|
||||
hash_defaults.emplace_back(last);
|
||||
}
|
||||
|
||||
std::reverse(hash_defaults.begin(), hash_defaults.end());
|
||||
}
|
||||
|
||||
template<typename HashT>
|
||||
merkle_tree<HashT>::merkle_tree(const size_t depth,
|
||||
const size_t value_size,
|
||||
const std::vector<bit_vector> &contents_as_vector) :
|
||||
merkle_tree<HashT>(depth, value_size)
|
||||
{
|
||||
assert(log2(contents_as_vector.size()) <= depth);
|
||||
for (size_t address = 0; address < contents_as_vector.size(); ++address)
|
||||
{
|
||||
const size_t idx = address + (1ul<<depth) - 1;
|
||||
values[idx] = contents_as_vector[address];
|
||||
hashes[idx] = contents_as_vector[address];
|
||||
hashes[idx].resize(digest_size);
|
||||
}
|
||||
|
||||
size_t idx_begin = (1ul<<depth) - 1;
|
||||
size_t idx_end = contents_as_vector.size() + ((1ul<<depth) - 1);
|
||||
|
||||
for (int layer = depth; layer > 0; --layer)
|
||||
{
|
||||
for (size_t idx = idx_begin; idx < idx_end; idx += 2)
|
||||
{
|
||||
hash_value_type l = hashes[idx]; // this is sound, because idx_begin is always a left child
|
||||
hash_value_type r = (idx + 1 < idx_end ? hashes[idx+1] : hash_defaults[layer]);
|
||||
|
||||
hash_value_type h = two_to_one_CRH<HashT>(l, r);
|
||||
hashes[(idx-1)/2] = h;
|
||||
}
|
||||
|
||||
idx_begin = (idx_begin-1)/2;
|
||||
idx_end = (idx_end-1)/2;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename HashT>
|
||||
merkle_tree<HashT>::merkle_tree(const size_t depth,
|
||||
const size_t value_size,
|
||||
const std::map<size_t, bit_vector> &contents) :
|
||||
merkle_tree<HashT>(depth, value_size)
|
||||
{
|
||||
|
||||
if (!contents.empty())
|
||||
{
|
||||
assert(contents.rbegin()->first < 1ul<<depth);
|
||||
|
||||
for (auto it = contents.begin(); it != contents.end(); ++it)
|
||||
{
|
||||
const size_t address = it->first;
|
||||
const bit_vector value = it->second;
|
||||
const size_t idx = address + (1ul<<depth) - 1;
|
||||
|
||||
values[address] = value;
|
||||
hashes[idx] = value;
|
||||
hashes[idx].resize(digest_size);
|
||||
}
|
||||
|
||||
auto last_it = hashes.end();
|
||||
|
||||
for (int layer = depth; layer > 0; --layer)
|
||||
{
|
||||
auto next_last_it = hashes.begin();
|
||||
|
||||
for (auto it = hashes.begin(); it != last_it; ++it)
|
||||
{
|
||||
const size_t idx = it->first;
|
||||
const hash_value_type hash = it->second;
|
||||
|
||||
if (idx % 2 == 0)
|
||||
{
|
||||
// this is the right child of its parent and by invariant we are missing the left child
|
||||
hashes[(idx-1)/2] = two_to_one_CRH<HashT>(hash_defaults[layer], hash);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (std::next(it) == last_it || std::next(it)->first != idx + 1)
|
||||
{
|
||||
// this is the left child of its parent and is missing its right child
|
||||
hashes[(idx-1)/2] = two_to_one_CRH<HashT>(hash, hash_defaults[layer]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// typical case: this is the left child of the parent and adjecent to it there is a right child
|
||||
hashes[(idx-1)/2] = two_to_one_CRH<HashT>(hash, std::next(it)->second);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
last_it = next_last_it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename HashT>
|
||||
bit_vector merkle_tree<HashT>::get_value(const size_t address) const
|
||||
{
|
||||
assert(log2(address) <= depth);
|
||||
|
||||
auto it = values.find(address);
|
||||
bit_vector padded_result = (it == values.end() ? bit_vector(digest_size) : it->second);
|
||||
padded_result.resize(value_size);
|
||||
|
||||
return padded_result;
|
||||
}
|
||||
|
||||
template<typename HashT>
|
||||
void merkle_tree<HashT>::set_value(const size_t address,
|
||||
const bit_vector &value)
|
||||
{
|
||||
assert(log2(address) <= depth);
|
||||
size_t idx = address + (1ul<<depth) - 1;
|
||||
|
||||
assert(value.size() == value_size);
|
||||
values[address] = value;
|
||||
hashes[idx] = value;
|
||||
hashes[idx].resize(digest_size);
|
||||
|
||||
for (int layer = depth-1; layer >=0; --layer)
|
||||
{
|
||||
idx = (idx-1)/2;
|
||||
|
||||
auto it = hashes.find(2*idx+1);
|
||||
hash_value_type l = (it == hashes.end() ? hash_defaults[layer+1] : it->second);
|
||||
|
||||
it = hashes.find(2*idx+2);
|
||||
hash_value_type r = (it == hashes.end() ? hash_defaults[layer+1] : it->second);
|
||||
|
||||
hash_value_type h = two_to_one_CRH<HashT>(l, r);
|
||||
hashes[idx] = h;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename HashT>
|
||||
typename HashT::hash_value_type merkle_tree<HashT>::get_root() const
|
||||
{
|
||||
auto it = hashes.find(0);
|
||||
return (it == hashes.end() ? hash_defaults[0] : it->second);
|
||||
}
|
||||
|
||||
template<typename HashT>
|
||||
typename HashT::merkle_authentication_path_type merkle_tree<HashT>::get_path(const size_t address) const
|
||||
{
|
||||
typename HashT::merkle_authentication_path_type result(depth);
|
||||
assert(log2(address) <= depth);
|
||||
size_t idx = address + (1ul<<depth) - 1;
|
||||
|
||||
for (size_t layer = depth; layer > 0; --layer)
|
||||
{
|
||||
size_t sibling_idx = ((idx + 1) ^ 1) - 1;
|
||||
auto it = hashes.find(sibling_idx);
|
||||
if (layer == depth)
|
||||
{
|
||||
auto it2 = values.find(sibling_idx - ((1ul<<depth) - 1));
|
||||
result[layer-1] = (it2 == values.end() ? bit_vector(value_size, false) : it2->second);
|
||||
result[layer-1].resize(digest_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
result[layer-1] = (it == hashes.end() ? hash_defaults[layer] : it->second);
|
||||
}
|
||||
|
||||
idx = (idx-1)/2;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename HashT>
|
||||
void merkle_tree<HashT>::dump() const
|
||||
{
|
||||
for (size_t i = 0; i < 1ul<<depth; ++i)
|
||||
{
|
||||
auto it = values.find(i);
|
||||
printf("[%zu] -> ", i);
|
||||
const bit_vector value = (it == values.end() ? bit_vector(value_size) : it->second);
|
||||
for (bool b : value)
|
||||
{
|
||||
printf("%d", b ? 1 : 0);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
} // libsnark
|
||||
|
||||
#endif // MERKLE_TREE_TCC
|
||||
79
src/common/data_structures/sparse_vector.hpp
Normal file
79
src/common/data_structures/sparse_vector.hpp
Normal file
@@ -0,0 +1,79 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
|
||||
Declaration of interfaces for a sparse vector.
|
||||
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef SPARSE_VECTOR_HPP_
|
||||
#define SPARSE_VECTOR_HPP_
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace libsnark {
|
||||
|
||||
template<typename T>
|
||||
struct sparse_vector;
|
||||
|
||||
template<typename T>
|
||||
std::ostream& operator<<(std::ostream &out, const sparse_vector<T> &v);
|
||||
|
||||
template<typename T>
|
||||
std::istream& operator>>(std::istream &in, sparse_vector<T> &v);
|
||||
|
||||
/**
|
||||
* A sparse vector is a list of indices along with corresponding values.
|
||||
* The indices are selected from the set {0,1,...,domain_size-1}.
|
||||
*/
|
||||
template<typename T>
|
||||
struct sparse_vector {
|
||||
|
||||
std::vector<size_t> indices;
|
||||
std::vector<T> values;
|
||||
size_t domain_size_ = 0;
|
||||
|
||||
sparse_vector() = default;
|
||||
sparse_vector(const sparse_vector<T> &other) = default;
|
||||
sparse_vector(sparse_vector<T> &&other) = default;
|
||||
sparse_vector(std::vector<T> &&v); /* constructor from std::vector */
|
||||
|
||||
sparse_vector<T>& operator=(const sparse_vector<T> &other) = default;
|
||||
sparse_vector<T>& operator=(sparse_vector<T> &&other) = default;
|
||||
|
||||
T operator[](const size_t idx) const;
|
||||
|
||||
bool operator==(const sparse_vector<T> &other) const;
|
||||
bool operator==(const std::vector<T> &other) const;
|
||||
|
||||
bool is_valid() const;
|
||||
bool empty() const;
|
||||
|
||||
size_t domain_size() const; // return domain_size_
|
||||
size_t size() const; // return the number of indices (representing the number of non-zero entries)
|
||||
size_t size_in_bits() const; // return the number bits needed to store the sparse vector
|
||||
|
||||
/* return a pair consisting of the accumulated value and the sparse vector of non-accumuated values */
|
||||
template<typename FieldT>
|
||||
std::pair<T, sparse_vector<T> > accumulate(const typename std::vector<FieldT>::const_iterator &it_begin,
|
||||
const typename std::vector<FieldT>::const_iterator &it_end,
|
||||
const size_t offset) const;
|
||||
|
||||
friend std::ostream& operator<< <T>(std::ostream &out, const sparse_vector<T> &v);
|
||||
friend std::istream& operator>> <T>(std::istream &in, sparse_vector<T> &v);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
std::ostream& operator<<(std::ostream& out, const sparse_vector<T> &v);
|
||||
|
||||
template<typename T>
|
||||
std::istream& operator>>(std::istream& in, sparse_vector<T> &v);
|
||||
|
||||
} // libsnark
|
||||
|
||||
#include "common/data_structures/sparse_vector.tcc"
|
||||
|
||||
#endif // SPARSE_VECTOR_HPP_
|
||||
316
src/common/data_structures/sparse_vector.tcc
Normal file
316
src/common/data_structures/sparse_vector.tcc
Normal file
@@ -0,0 +1,316 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
|
||||
Implementation of interfaces for a sparse vector.
|
||||
|
||||
See sparse_vector.hpp .
|
||||
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef SPARSE_VECTOR_TCC_
|
||||
#define SPARSE_VECTOR_TCC_
|
||||
|
||||
#include "algebra/scalar_multiplication/multiexp.hpp"
|
||||
|
||||
#include <numeric>
|
||||
|
||||
namespace libsnark {
|
||||
|
||||
template<typename T>
|
||||
sparse_vector<T>::sparse_vector(std::vector<T> &&v) :
|
||||
values(std::move(v)), domain_size_(values.size())
|
||||
{
|
||||
indices.resize(domain_size_);
|
||||
std::iota(indices.begin(), indices.end(), 0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T sparse_vector<T>::operator[](const size_t idx) const
|
||||
{
|
||||
auto it = std::lower_bound(indices.begin(), indices.end(), idx);
|
||||
return (it != indices.end() && *it == idx) ? values[it - indices.begin()] : T();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool sparse_vector<T>::operator==(const sparse_vector<T> &other) const
|
||||
{
|
||||
if (this->domain_size_ != other.domain_size_)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t this_pos = 0, other_pos = 0;
|
||||
while (this_pos < this->indices.size() && other_pos < other.indices.size())
|
||||
{
|
||||
if (this->indices[this_pos] == other.indices[other_pos])
|
||||
{
|
||||
if (this->values[this_pos] != other.values[other_pos])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
++this_pos;
|
||||
++other_pos;
|
||||
}
|
||||
else if (this->indices[this_pos] < other.indices[other_pos])
|
||||
{
|
||||
if (!this->values[this_pos].is_zero())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
++this_pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!other.values[other_pos].is_zero())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
++other_pos;
|
||||
}
|
||||
}
|
||||
|
||||
/* at least one of the vectors has been exhausted, so other must be empty */
|
||||
while (this_pos < this->indices.size())
|
||||
{
|
||||
if (!this->values[this_pos].is_zero())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
++this_pos;
|
||||
}
|
||||
|
||||
while (other_pos < other.indices.size())
|
||||
{
|
||||
if (!other.values[other_pos].is_zero())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
++other_pos;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool sparse_vector<T>::operator==(const std::vector<T> &other) const
|
||||
{
|
||||
if (this->domain_size_ < other.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t j = 0;
|
||||
for (size_t i = 0; i < other.size(); ++i)
|
||||
{
|
||||
if (this->indices[j] == i)
|
||||
{
|
||||
if (this->values[j] != other[j])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
++j;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!other[j].is_zero())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool sparse_vector<T>::is_valid() const
|
||||
{
|
||||
if (values.size() == indices.size() && values.size() <= domain_size_)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i + 1 < indices.size(); ++i)
|
||||
{
|
||||
if (indices[i] >= indices[i+1])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!indices.empty() && indices[indices.size()-1] >= domain_size_)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool sparse_vector<T>::empty() const
|
||||
{
|
||||
return indices.empty();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
size_t sparse_vector<T>::domain_size() const
|
||||
{
|
||||
return domain_size_;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
size_t sparse_vector<T>::size() const
|
||||
{
|
||||
return indices.size();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
size_t sparse_vector<T>::size_in_bits() const
|
||||
{
|
||||
return indices.size() * (sizeof(size_t) * 8 + T::size_in_bits());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename FieldT>
|
||||
std::pair<T, sparse_vector<T> > sparse_vector<T>::accumulate(const typename std::vector<FieldT>::const_iterator &it_begin,
|
||||
const typename std::vector<FieldT>::const_iterator &it_end,
|
||||
const size_t offset) const
|
||||
{
|
||||
// TODO: does not really belong here.
|
||||
const size_t chunks = 1;
|
||||
const bool use_multiexp = true;
|
||||
|
||||
T accumulated_value = T::zero();
|
||||
sparse_vector<T> resulting_vector;
|
||||
resulting_vector.domain_size_ = domain_size_;
|
||||
|
||||
const size_t range_len = it_end - it_begin;
|
||||
bool in_block = false;
|
||||
size_t first_pos = -1, last_pos = -1; // g++ -flto emits unitialized warning, even though in_block guards for such cases.
|
||||
|
||||
for (size_t i = 0; i < indices.size(); ++i)
|
||||
{
|
||||
const bool matching_pos = (offset <= indices[i] && indices[i] < offset + range_len);
|
||||
// printf("i = %zu, pos[i] = %zu, offset = %zu, w_size = %zu\n", i, indices[i], offset, w_size);
|
||||
bool copy_over;
|
||||
|
||||
if (in_block)
|
||||
{
|
||||
if (matching_pos && last_pos == i-1)
|
||||
{
|
||||
// block can be extended, do it
|
||||
last_pos = i;
|
||||
copy_over = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// block has ended here
|
||||
in_block = false;
|
||||
copy_over = true;
|
||||
|
||||
#ifdef DEBUG
|
||||
print_indent(); printf("doing multiexp for w_%zu ... w_%zu\n", indices[first_pos], indices[last_pos]);
|
||||
#endif
|
||||
accumulated_value = accumulated_value + multi_exp<T, FieldT>(values.begin() + first_pos,
|
||||
values.begin() + last_pos + 1,
|
||||
it_begin + (indices[first_pos] - offset),
|
||||
it_begin + (indices[last_pos] - offset) + 1,
|
||||
chunks, use_multiexp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (matching_pos)
|
||||
{
|
||||
// block can be started
|
||||
first_pos = i;
|
||||
last_pos = i;
|
||||
in_block = true;
|
||||
copy_over = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
copy_over = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (copy_over)
|
||||
{
|
||||
resulting_vector.indices.emplace_back(indices[i]);
|
||||
resulting_vector.values.emplace_back(values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (in_block)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
print_indent(); printf("doing multiexp for w_%zu ... w_%zu\n", indices[first_pos], indices[last_pos]);
|
||||
#endif
|
||||
accumulated_value = accumulated_value + multi_exp<T, FieldT>(values.begin() + first_pos,
|
||||
values.begin() + last_pos + 1,
|
||||
it_begin + (indices[first_pos] - offset),
|
||||
it_begin + (indices[last_pos] - offset) + 1,
|
||||
chunks, use_multiexp);
|
||||
}
|
||||
|
||||
return std::make_pair(accumulated_value, resulting_vector);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::ostream& operator<<(std::ostream& out, const sparse_vector<T> &v)
|
||||
{
|
||||
out << v.domain_size_ << "\n";
|
||||
out << v.indices.size() << "\n";
|
||||
for (const size_t& i : v.indices)
|
||||
{
|
||||
out << i << "\n";
|
||||
}
|
||||
|
||||
out << v.values.size() << "\n";
|
||||
for (const T& t : v.values)
|
||||
{
|
||||
out << t << OUTPUT_NEWLINE;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::istream& operator>>(std::istream& in, sparse_vector<T> &v)
|
||||
{
|
||||
in >> v.domain_size_;
|
||||
consume_newline(in);
|
||||
|
||||
size_t s;
|
||||
in >> s;
|
||||
consume_newline(in);
|
||||
v.indices.resize(s);
|
||||
for (size_t i = 0; i < s; ++i)
|
||||
{
|
||||
in >> v.indices[i];
|
||||
consume_newline(in);
|
||||
}
|
||||
|
||||
v.values.clear();
|
||||
in >> s;
|
||||
consume_newline(in);
|
||||
v.values.reserve(s);
|
||||
|
||||
for (size_t i = 0; i < s; ++i)
|
||||
{
|
||||
T t;
|
||||
in >> t;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
v.values.emplace_back(t);
|
||||
}
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
} // libsnark
|
||||
|
||||
#endif // SPARSE_VECTOR_TCC_
|
||||
53
src/common/default_types/ec_pp.hpp
Normal file
53
src/common/default_types/ec_pp.hpp
Normal file
@@ -0,0 +1,53 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
|
||||
This file defines default_ec_pp based on the CURVE=... make flag, which selects
|
||||
which elliptic curve is used to implement group arithmetic and pairings.
|
||||
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef EC_PP_HPP_
|
||||
#define EC_PP_HPP_
|
||||
|
||||
/************************ Pick the elliptic curve ****************************/
|
||||
|
||||
#ifdef CURVE_ALT_BN128
|
||||
#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp"
|
||||
namespace libsnark {
|
||||
typedef alt_bn128_pp default_ec_pp;
|
||||
} // libsnark
|
||||
#endif
|
||||
|
||||
#ifdef CURVE_BN128
|
||||
#include "algebra/curves/bn128/bn128_pp.hpp"
|
||||
namespace libsnark {
|
||||
typedef bn128_pp default_ec_pp;
|
||||
} // libsnark
|
||||
#endif
|
||||
|
||||
#ifdef CURVE_EDWARDS
|
||||
#include "algebra/curves/edwards/edwards_pp.hpp"
|
||||
namespace libsnark {
|
||||
typedef edwards_pp default_ec_pp;
|
||||
} // libsnark
|
||||
#endif
|
||||
|
||||
#ifdef CURVE_MNT4
|
||||
#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp"
|
||||
namespace libsnark {
|
||||
typedef mnt4_pp default_ec_pp;
|
||||
} // libsnark
|
||||
#endif
|
||||
|
||||
#ifdef CURVE_MNT6
|
||||
#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp"
|
||||
namespace libsnark {
|
||||
typedef mnt6_pp default_ec_pp;
|
||||
} // libsnark
|
||||
#endif
|
||||
|
||||
#endif // EC_PP_HPP_
|
||||
22
src/common/default_types/r1cs_ppzksnark_pp.hpp
Normal file
22
src/common/default_types/r1cs_ppzksnark_pp.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
|
||||
This file defines default_r1cs_ppzksnark_pp based on the elliptic curve
|
||||
choice selected in ec_pp.hpp.
|
||||
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef R1CS_PPZKSNARK_PP_HPP_
|
||||
#define R1CS_PPZKSNARK_PP_HPP_
|
||||
|
||||
#include "common/default_types/ec_pp.hpp"
|
||||
|
||||
namespace libsnark {
|
||||
typedef default_ec_pp default_r1cs_ppzksnark_pp;
|
||||
} // libsnark
|
||||
|
||||
#endif // R1CS_PPZKSNARK_PP_HPP_
|
||||
379
src/common/profiling.cpp
Normal file
379
src/common/profiling.cpp
Normal file
@@ -0,0 +1,379 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
|
||||
Implementation of functions for profiling code blocks.
|
||||
|
||||
See profiling.hpp .
|
||||
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
|
||||
#include "common/profiling.hpp"
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <ctime>
|
||||
#include "common/default_types/ec_pp.hpp"
|
||||
#include "common/utils.hpp"
|
||||
|
||||
#ifndef NO_PROCPS
|
||||
#include <proc/readproc.h>
|
||||
#endif
|
||||
|
||||
namespace libsnark {
|
||||
|
||||
long long get_nsec_time()
|
||||
{
|
||||
auto timepoint = std::chrono::high_resolution_clock::now();
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(timepoint.time_since_epoch()).count();
|
||||
}
|
||||
|
||||
/* Return total CPU time consumsed by all threads of the process, in nanoseconds. */
|
||||
long long get_nsec_cpu_time()
|
||||
{
|
||||
::timespec ts;
|
||||
if ( ::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) )
|
||||
throw ::std::runtime_error("clock_gettime(CLOCK_PROCESS_CPUTIME_ID) failed");
|
||||
// If we expected this to work, don't silently ignore failures, because that would hide the problem and incur an unnecessarily system-call overhead. So if we ever observe this exception, we should probably add a suitable #ifdef .
|
||||
//TODO: clock_gettime(CLOCK_PROCESS_CPUTIME_ID) is not supported by native Windows. What about Cygwin? Should we #ifdef on CLOCK_PROCESS_CPUTIME_ID or on __linux__?
|
||||
return ts.tv_sec * 1000000000ll + ts.tv_nsec;
|
||||
}
|
||||
|
||||
long long start_time, last_time;
|
||||
long long start_cpu_time, last_cpu_time;
|
||||
|
||||
void start_profiling()
|
||||
{
|
||||
printf("Reset time counters for profiling\n");
|
||||
|
||||
last_time = start_time = get_nsec_time();
|
||||
last_cpu_time = start_cpu_time = get_nsec_cpu_time();
|
||||
}
|
||||
|
||||
std::map<std::string, size_t> invocation_counts;
|
||||
std::map<std::string, long long> enter_times;
|
||||
std::map<std::string, long long> last_times;
|
||||
std::map<std::string, long long> cumulative_times;
|
||||
//TODO: Instead of analogous maps for time and cpu_time, use a single struct-valued map
|
||||
std::map<std::string, long long> enter_cpu_times;
|
||||
std::map<std::string, long long> last_cpu_times;
|
||||
std::map<std::pair<std::string, std::string>, long long> op_counts;
|
||||
std::map<std::pair<std::string, std::string>, long long> cumulative_op_counts; // ((msg, data_point), value)
|
||||
// TODO: Convert op_counts and cumulative_op_counts from pair to structs
|
||||
size_t indentation = 0;
|
||||
|
||||
std::vector<std::string> block_names;
|
||||
|
||||
std::list<std::pair<std::string, long long*> > op_data_points = {
|
||||
#ifdef PROFILE_OP_COUNTS
|
||||
std::make_pair("Fradd", &Fr<default_ec_pp>::add_cnt),
|
||||
std::make_pair("Frsub", &Fr<default_ec_pp>::sub_cnt),
|
||||
std::make_pair("Frmul", &Fr<default_ec_pp>::mul_cnt),
|
||||
std::make_pair("Frinv", &Fr<default_ec_pp>::inv_cnt),
|
||||
std::make_pair("Fqadd", &Fq<default_ec_pp>::add_cnt),
|
||||
std::make_pair("Fqsub", &Fq<default_ec_pp>::sub_cnt),
|
||||
std::make_pair("Fqmul", &Fq<default_ec_pp>::mul_cnt),
|
||||
std::make_pair("Fqinv", &Fq<default_ec_pp>::inv_cnt),
|
||||
std::make_pair("G1add", &G1<default_ec_pp>::add_cnt),
|
||||
std::make_pair("G1dbl", &G1<default_ec_pp>::dbl_cnt),
|
||||
std::make_pair("G2add", &G2<default_ec_pp>::add_cnt),
|
||||
std::make_pair("G2dbl", &G2<default_ec_pp>::dbl_cnt)
|
||||
#endif
|
||||
};
|
||||
|
||||
bool inhibit_profiling_info = false;
|
||||
bool inhibit_profiling_counters = false;
|
||||
|
||||
void clear_profiling_counters()
|
||||
{
|
||||
invocation_counts.clear();
|
||||
last_times.clear();
|
||||
last_cpu_times.clear();
|
||||
cumulative_times.clear();
|
||||
}
|
||||
|
||||
void print_cumulative_time_entry(const std::string &key, const long long factor)
|
||||
{
|
||||
const double total_ms = (cumulative_times.at(key) * 1e-6);
|
||||
const size_t cnt = invocation_counts.at(key);
|
||||
const double avg_ms = total_ms / cnt;
|
||||
printf(" %-45s: %12.5fms = %lld * %0.5fms (%zu invocations, %0.5fms = %lld * %0.5fms per invocation)\n", key.c_str(), total_ms, factor, total_ms/factor, cnt, avg_ms, factor, avg_ms/factor);
|
||||
}
|
||||
|
||||
void print_cumulative_times(const long long factor)
|
||||
{
|
||||
printf("Dumping times:\n");
|
||||
for (auto& kv : cumulative_times)
|
||||
{
|
||||
print_cumulative_time_entry(kv.first, factor);
|
||||
}
|
||||
}
|
||||
|
||||
void print_cumulative_op_counts(const bool only_fq)
|
||||
{
|
||||
#ifdef PROFILE_OP_COUNTS
|
||||
printf("Dumping operation counts:\n");
|
||||
for (auto& msg : invocation_counts)
|
||||
{
|
||||
printf(" %-45s: ", msg.first.c_str());
|
||||
bool first = true;
|
||||
for (auto& data_point : op_data_points)
|
||||
{
|
||||
if (only_fq && data_point.first.compare(0, 2, "Fq") != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!first)
|
||||
{
|
||||
printf(", ");
|
||||
}
|
||||
printf("%-5s = %7.0f (%3zu)",
|
||||
data_point.first.c_str(),
|
||||
1. * cumulative_op_counts[std::make_pair(msg.first, data_point.first)] / msg.second,
|
||||
msg.second);
|
||||
first = false;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#else
|
||||
UNUSED(only_fq);
|
||||
#endif
|
||||
}
|
||||
|
||||
void print_op_profiling(const std::string &msg)
|
||||
{
|
||||
#ifdef PROFILE_OP_COUNTS
|
||||
printf("\n");
|
||||
print_indent();
|
||||
|
||||
printf("(opcounts) = (");
|
||||
bool first = true;
|
||||
for (std::pair<std::string, long long*> p : op_data_points)
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
printf(", ");
|
||||
}
|
||||
|
||||
printf("%s=%lld", p.first.c_str(), *(p.second)-op_counts[std::make_pair(msg, p.first)]);
|
||||
first = false;
|
||||
}
|
||||
printf(")");
|
||||
#else
|
||||
UNUSED(msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void print_times_from_last_and_start(long long now, long long last,
|
||||
long long cpu_now, long long cpu_last)
|
||||
{
|
||||
long long time_from_start = now - start_time;
|
||||
long long time_from_last = now - last;
|
||||
|
||||
long long cpu_time_from_start = cpu_now - start_cpu_time;
|
||||
long long cpu_time_from_last = cpu_now - cpu_last;
|
||||
|
||||
if (time_from_last != 0) {
|
||||
double parallelism_from_last = 1.0 * cpu_time_from_last / time_from_last;
|
||||
printf("[%0.4fs x%0.2f]", time_from_last * 1e-9, parallelism_from_last);
|
||||
} else {
|
||||
printf("[ ]");
|
||||
}
|
||||
if (time_from_start != 0) {
|
||||
double parallelism_from_start = 1.0 * cpu_time_from_start / time_from_start;
|
||||
printf("\t(%0.4fs x%0.2f from start)", time_from_start * 1e-9, parallelism_from_start);
|
||||
}
|
||||
}
|
||||
|
||||
void print_time(const char* msg)
|
||||
{
|
||||
if (inhibit_profiling_info)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
long long now = get_nsec_time();
|
||||
long long cpu_now = get_nsec_cpu_time();
|
||||
|
||||
printf("%-35s\t", msg);
|
||||
print_times_from_last_and_start(now, last_time, cpu_now, last_cpu_time);
|
||||
#ifdef PROFILE_OP_COUNTS
|
||||
print_op_profiling(msg);
|
||||
#endif
|
||||
printf("\n");
|
||||
|
||||
fflush(stdout);
|
||||
last_time = now;
|
||||
last_cpu_time = cpu_now;
|
||||
}
|
||||
|
||||
void print_header(const char *msg)
|
||||
{
|
||||
printf("\n================================================================================\n");
|
||||
printf("%s\n", msg);
|
||||
printf("================================================================================\n\n");
|
||||
}
|
||||
|
||||
void print_indent()
|
||||
{
|
||||
for (size_t i = 0; i < indentation; ++i)
|
||||
{
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
|
||||
void op_profiling_enter(const std::string &msg)
|
||||
{
|
||||
for (std::pair<std::string, long long*> p : op_data_points)
|
||||
{
|
||||
op_counts[std::make_pair(msg, p.first)] = *(p.second);
|
||||
}
|
||||
}
|
||||
|
||||
void enter_block(const std::string &msg, const bool indent)
|
||||
{
|
||||
if (inhibit_profiling_counters)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
block_names.emplace_back(msg);
|
||||
long long t = get_nsec_time();
|
||||
enter_times[msg] = t;
|
||||
long long cpu_t = get_nsec_cpu_time();
|
||||
enter_cpu_times[msg] = cpu_t;
|
||||
|
||||
if (inhibit_profiling_info)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MULTICORE
|
||||
#pragma omp critical
|
||||
#endif
|
||||
{
|
||||
op_profiling_enter(msg);
|
||||
|
||||
print_indent();
|
||||
printf("(enter) %-35s\t", msg.c_str());
|
||||
print_times_from_last_and_start(t, t, cpu_t, cpu_t);
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
|
||||
if (indent)
|
||||
{
|
||||
++indentation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void leave_block(const std::string &msg, const bool indent)
|
||||
{
|
||||
if (inhibit_profiling_counters)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef MULTICORE
|
||||
assert(*(--block_names.end()) == msg);
|
||||
#endif
|
||||
block_names.pop_back();
|
||||
|
||||
++invocation_counts[msg];
|
||||
|
||||
long long t = get_nsec_time();
|
||||
last_times[msg] = (t - enter_times[msg]);
|
||||
cumulative_times[msg] += (t - enter_times[msg]);
|
||||
|
||||
long long cpu_t = get_nsec_cpu_time();
|
||||
last_cpu_times[msg] = (cpu_t - enter_cpu_times[msg]);
|
||||
|
||||
#ifdef PROFILE_OP_COUNTS
|
||||
for (std::pair<std::string, long long*> p : op_data_points)
|
||||
{
|
||||
cumulative_op_counts[std::make_pair(msg, p.first)] += *(p.second)-op_counts[std::make_pair(msg, p.first)];
|
||||
}
|
||||
#endif
|
||||
|
||||
if (inhibit_profiling_info)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MULTICORE
|
||||
#pragma omp critical
|
||||
#endif
|
||||
{
|
||||
if (indent)
|
||||
{
|
||||
--indentation;
|
||||
}
|
||||
|
||||
print_indent();
|
||||
printf("(leave) %-35s\t", msg.c_str());
|
||||
print_times_from_last_and_start(t, enter_times[msg], cpu_t, enter_cpu_times[msg]);
|
||||
print_op_profiling(msg);
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
void print_mem(const std::string &s)
|
||||
{
|
||||
#ifndef NO_PROCPS
|
||||
struct proc_t usage;
|
||||
look_up_our_self(&usage);
|
||||
if (s.empty())
|
||||
{
|
||||
printf("* Peak vsize (physical memory+swap) in mebibytes: %lu\n", usage.vsize >> 20);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("* Peak vsize (physical memory+swap) in mebibytes (%s): %lu\n", s.c_str(), usage.vsize >> 20);
|
||||
}
|
||||
#else
|
||||
printf("* Memory profiling not supported in NO_PROCPS mode\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void print_compilation_info()
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
printf("g++ version: %s\n", __VERSION__);
|
||||
//printf("Compiled on %s %s\n", __DATE__, __TIME__);
|
||||
#endif
|
||||
#ifdef STATIC
|
||||
printf("STATIC: yes\n");
|
||||
#else
|
||||
printf("STATIC: no\n");
|
||||
#endif
|
||||
#ifdef MULTICORE
|
||||
printf("MULTICORE: yes\n");
|
||||
#else
|
||||
printf("MULTICORE: no\n");
|
||||
#endif
|
||||
#ifdef DEBUG
|
||||
printf("DEBUG: yes\n");
|
||||
#else
|
||||
printf("DEBUG: no\n");
|
||||
#endif
|
||||
#ifdef PROFILE_OP_COUNTS
|
||||
printf("PROFILE_OP_COUNTS: yes\n");
|
||||
#else
|
||||
printf("PROFILE_OP_COUNTS: no\n");
|
||||
#endif
|
||||
#ifdef _GLIBCXX_DEBUG
|
||||
printf("_GLIBCXX_DEBUG: yes\n");
|
||||
#else
|
||||
printf("_GLIBCXX_DEBUG: no\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // libsnark
|
||||
51
src/common/profiling.hpp
Normal file
51
src/common/profiling.hpp
Normal file
@@ -0,0 +1,51 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
|
||||
Declaration of functions for profiling code blocks.
|
||||
|
||||
Reports time, operation counts, memory usage, and others.
|
||||
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef PROFILING_HPP_
|
||||
#define PROFILING_HPP_
|
||||
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace libsnark {
|
||||
|
||||
void start_profiling();
|
||||
long long get_nsec_time();
|
||||
void print_time(const char* msg);
|
||||
void print_header(const char* msg);
|
||||
|
||||
void print_indent();
|
||||
|
||||
extern bool inhibit_profiling_info;
|
||||
extern bool inhibit_profiling_counters;
|
||||
extern std::map<std::string, size_t> invocation_counts;
|
||||
extern std::map<std::string, long long> last_times;
|
||||
extern std::map<std::string, long long> cumulative_times;
|
||||
|
||||
void clear_profiling_counters();
|
||||
|
||||
void print_cumulative_time_entry(const std::string &key, const long long factor=1);
|
||||
void print_cumulative_times(const long long factor=1);
|
||||
void print_cumulative_op_counts(const bool only_fq=false);
|
||||
|
||||
void enter_block(const std::string &msg, const bool indent=true);
|
||||
void leave_block(const std::string &msg, const bool indent=true);
|
||||
|
||||
void print_mem(const std::string &s = "");
|
||||
void print_compilation_info();
|
||||
|
||||
} // libsnark
|
||||
|
||||
#endif // PROFILING_HPP_
|
||||
104
src/common/serialization.hpp
Normal file
104
src/common/serialization.hpp
Normal file
@@ -0,0 +1,104 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
|
||||
Declaration of serialization routines and constants.
|
||||
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef SERIALIZATION_HPP_
|
||||
#define SERIALIZATION_HPP_
|
||||
|
||||
#include <istream>
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace libsnark {
|
||||
|
||||
/*
|
||||
* @todo
|
||||
* The serialization is fragile. Shoud be rewritten using a standard, portable-format
|
||||
* library like boost::serialize.
|
||||
*
|
||||
* However, for now the following conventions are used within the code.
|
||||
*
|
||||
* All algebraic objects support either binary or decimal output using
|
||||
* the standard C++ stream operators (operator<<, operator>>).
|
||||
*
|
||||
* The binary mode is activated by defining a BINARY_OUTPUT
|
||||
* preprocessor macro (e.g. g++ -DBINARY_OUTPUT ...).
|
||||
*
|
||||
* Binary output assumes that the stream is to be binary read at its
|
||||
* current position so any white space should be consumed beforehand.
|
||||
*
|
||||
* Consecutive algebraic objects are separated by OUTPUT_NEWLINE and
|
||||
* within themselves (e.g. X and Y coordinates for field elements) with
|
||||
* OUTPUT_SEPARATOR (as defined below).
|
||||
*
|
||||
* Therefore to dump two integers, two Fp elements and another integer
|
||||
* one would:
|
||||
*
|
||||
* out << 3 << "\n";
|
||||
* out << 4 << "\n";
|
||||
* out << FieldT(56) << OUTPUT_NEWLINE;
|
||||
* out << FieldT(78) << OUTPUT_NEWLINE;
|
||||
* out << 9 << "\n";
|
||||
*
|
||||
* Then reading back it its reader's responsibility (!) to consume "\n"
|
||||
* after 4, but Fp::operator<< will correctly consume OUTPUT_NEWLINE.
|
||||
*
|
||||
* The reader should also consume "\n" after 9, so that another field
|
||||
* element can be properly chained. This is especially important for
|
||||
* binary output.
|
||||
*
|
||||
* The binary serialization of algebraic objects is currently *not*
|
||||
* portable between machines of different word sizes.
|
||||
*/
|
||||
|
||||
#ifdef BINARY_OUTPUT
|
||||
#define OUTPUT_NEWLINE ""
|
||||
#define OUTPUT_SEPARATOR ""
|
||||
#else
|
||||
#define OUTPUT_NEWLINE "\n"
|
||||
#define OUTPUT_SEPARATOR " "
|
||||
#endif
|
||||
|
||||
inline void consume_newline(std::istream &in);
|
||||
inline void consume_OUTPUT_NEWLINE(std::istream &in);
|
||||
inline void consume_OUTPUT_SEPARATOR(std::istream &in);
|
||||
|
||||
inline void output_bool(std::ostream &out, const bool b);
|
||||
|
||||
inline void output_bool_vector(std::ostream &out, const std::vector<bool> &v);
|
||||
|
||||
template<typename T>
|
||||
T reserialize(const T &obj);
|
||||
|
||||
template<typename T>
|
||||
std::ostream& operator<<(std::ostream& out, const std::vector<T> &v);
|
||||
|
||||
template<typename T>
|
||||
std::istream& operator>>(std::ostream& out, std::vector<T> &v);
|
||||
|
||||
template<typename T1, typename T2>
|
||||
std::ostream& operator<<(std::ostream& out, const std::map<T1, T2> &m);
|
||||
|
||||
template<typename T1, typename T2>
|
||||
std::istream& operator>>(std::istream& in, std::map<T1, T2> &m);
|
||||
|
||||
template<typename T>
|
||||
std::ostream& operator<<(std::ostream& out, const std::set<T> &s);
|
||||
|
||||
template<typename T>
|
||||
std::istream& operator>>(std::istream& in, std::set<T> &s);
|
||||
|
||||
} // libsnark
|
||||
|
||||
#include "common/serialization.tcc"
|
||||
|
||||
#endif // SERIALIZATION_HPP_
|
||||
180
src/common/serialization.tcc
Normal file
180
src/common/serialization.tcc
Normal file
@@ -0,0 +1,180 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
|
||||
Implementation of serialization routines.
|
||||
|
||||
See serialization.hpp .
|
||||
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef SERIALIZATION_TCC_
|
||||
#define SERIALIZATION_TCC_
|
||||
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
#include "common/utils.hpp"
|
||||
|
||||
namespace libsnark {
|
||||
|
||||
inline void consume_newline(std::istream &in)
|
||||
{
|
||||
char c;
|
||||
in.read(&c, 1);
|
||||
}
|
||||
|
||||
inline void consume_OUTPUT_NEWLINE(std::istream &in)
|
||||
{
|
||||
#ifdef BINARY_OUTPUT
|
||||
// nothing to consume
|
||||
UNUSED(in);
|
||||
#else
|
||||
char c;
|
||||
in.read(&c, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void consume_OUTPUT_SEPARATOR(std::istream &in)
|
||||
{
|
||||
#ifdef BINARY_OUTPUT
|
||||
// nothing to consume
|
||||
UNUSED(in);
|
||||
#else
|
||||
char c;
|
||||
in.read(&c, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void output_bool(std::ostream &out, const bool b)
|
||||
{
|
||||
out << (b ? 1 : 0) << "\n";
|
||||
}
|
||||
|
||||
inline void output_bool_vector(std::ostream &out, const std::vector<bool> &v)
|
||||
{
|
||||
out << v.size() << "\n";
|
||||
for (const bool b : v)
|
||||
{
|
||||
output_bool(out, b);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T reserialize(const T &obj)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << obj;
|
||||
T tmp;
|
||||
ss >> tmp;
|
||||
assert(obj == tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::ostream& operator<<(std::ostream& out, const std::vector<T> &v)
|
||||
{
|
||||
static_assert(!std::is_same<T, bool>::value, "this does not work for std::vector<bool>");
|
||||
out << v.size() << "\n";
|
||||
for (const T& t : v)
|
||||
{
|
||||
out << t << OUTPUT_NEWLINE;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::istream& operator>>(std::istream& in, std::vector<T> &v)
|
||||
{
|
||||
static_assert(!std::is_same<T, bool>::value, "this does not work for std::vector<bool>");
|
||||
size_t size;
|
||||
in >> size;
|
||||
consume_newline(in);
|
||||
|
||||
v.resize(0);
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
T elt;
|
||||
in >> elt;
|
||||
consume_OUTPUT_NEWLINE(in);
|
||||
v.push_back(elt);
|
||||
}
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
std::ostream& operator<<(std::ostream& out, const std::map<T1, T2> &m)
|
||||
{
|
||||
out << m.size() << "\n";
|
||||
|
||||
for (auto &it : m)
|
||||
{
|
||||
out << it.first << "\n";
|
||||
out << it.second << "\n";
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
std::istream& operator>>(std::istream& in, std::map<T1, T2> &m)
|
||||
{
|
||||
m.clear();
|
||||
size_t size;
|
||||
in >> size;
|
||||
consume_newline(in);
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
T1 k;
|
||||
T2 v;
|
||||
in >> k;
|
||||
consume_newline(in);
|
||||
in >> v;
|
||||
consume_newline(in);
|
||||
m[k] = v;
|
||||
}
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::ostream& operator<<(std::ostream& out, const std::set<T> &s)
|
||||
{
|
||||
out << s.size() << "\n";
|
||||
|
||||
for (auto &el : s)
|
||||
{
|
||||
out << el << "\n";
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
std::istream& operator>>(std::istream& in, std::set<T> &s)
|
||||
{
|
||||
s.clear();
|
||||
size_t size;
|
||||
in >> size;
|
||||
consume_newline(in);
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
T el;
|
||||
in >> el;
|
||||
consume_newline(in);
|
||||
s.insert(el);
|
||||
}
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // SERIALIZATION_TCC_
|
||||
26
src/common/template_utils.hpp
Normal file
26
src/common/template_utils.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
|
||||
Declaration of functions for supporting the use of templates.
|
||||
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef TEMPLATE_UTILS_HPP_
|
||||
#define TEMPLATE_UTILS_HPP_
|
||||
|
||||
namespace libsnark {
|
||||
|
||||
/* A commonly used SFINAE helper type */
|
||||
template<typename T>
|
||||
struct void_type
|
||||
{
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
} // libsnark
|
||||
|
||||
#endif // TEMPLATE_UTILS_HPP_
|
||||
102
src/common/utils.cpp
Normal file
102
src/common/utils.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
Implementation of misc math and serialization utility functions
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdarg>
|
||||
#include "common/utils.hpp"
|
||||
|
||||
namespace libsnark {
|
||||
|
||||
size_t log2(size_t n)
|
||||
/* returns ceil(log2(n)), so 1ul<<log2(n) is the smallest power of 2,
|
||||
that is not less than n. */
|
||||
{
|
||||
size_t r = ((n & (n-1)) == 0 ? 0 : 1); // add 1 if n is not power of 2
|
||||
|
||||
while (n > 1)
|
||||
{
|
||||
n >>= 1;
|
||||
r++;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
size_t bitreverse(size_t n, const size_t l)
|
||||
{
|
||||
size_t r = 0;
|
||||
for (size_t k = 0; k < l; ++k)
|
||||
{
|
||||
r = (r << 1) | (n & 1);
|
||||
n >>= 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
bit_vector int_list_to_bits(const std::initializer_list<unsigned long> &l, const size_t wordsize)
|
||||
{
|
||||
bit_vector res(wordsize*l.size());
|
||||
for (size_t i = 0; i < l.size(); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < wordsize; ++j)
|
||||
{
|
||||
res[i*wordsize + j] = (*(l.begin()+i) & (1ul<<(wordsize-1-j)));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
long long div_ceil(long long x, long long y)
|
||||
{
|
||||
return (x + (y-1)) / y;
|
||||
}
|
||||
|
||||
bool is_little_endian()
|
||||
{
|
||||
uint64_t a = 0x12345678;
|
||||
unsigned char *c = (unsigned char*)(&a);
|
||||
return (*c = 0x78);
|
||||
}
|
||||
|
||||
std::string FORMAT(const std::string &prefix, const char* format, ...)
|
||||
{
|
||||
const static size_t MAX_FMT = 256;
|
||||
char buf[MAX_FMT];
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(buf, MAX_FMT, format, args);
|
||||
va_end(args);
|
||||
|
||||
return prefix + std::string(buf);
|
||||
}
|
||||
|
||||
void serialize_bit_vector(std::ostream &out, const bit_vector &v)
|
||||
{
|
||||
out << v.size() << "\n";
|
||||
for (size_t i = 0; i < v.size(); ++i)
|
||||
{
|
||||
out << v[i] << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void deserialize_bit_vector(std::istream &in, bit_vector &v)
|
||||
{
|
||||
size_t size;
|
||||
in >> size;
|
||||
v.resize(size);
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
bool b;
|
||||
in >> b;
|
||||
v[i] = b;
|
||||
}
|
||||
}
|
||||
} // libsnark
|
||||
57
src/common/utils.hpp
Normal file
57
src/common/utils.hpp
Normal file
@@ -0,0 +1,57 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
Declaration of misc math and serialization utility functions
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef UTILS_HPP_
|
||||
#define UTILS_HPP_
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace libsnark {
|
||||
|
||||
typedef std::vector<bool> bit_vector;
|
||||
|
||||
/// returns ceil(log2(n)), so 1ul<<log2(n) is the smallest power of 2, that is not less than n
|
||||
size_t log2(size_t n);
|
||||
|
||||
inline size_t exp2(size_t k) { return 1ul << k; }
|
||||
|
||||
size_t bitreverse(size_t n, const size_t l);
|
||||
bit_vector int_list_to_bits(const std::initializer_list<unsigned long> &l, const size_t wordsize);
|
||||
long long div_ceil(long long x, long long y);
|
||||
|
||||
bool is_little_endian();
|
||||
|
||||
std::string FORMAT(const std::string &prefix, const char* format, ...);
|
||||
|
||||
/* A variadic template to suppress unused argument warnings */
|
||||
template<typename ... Types>
|
||||
void UNUSED(Types&&...) {}
|
||||
|
||||
#ifdef DEBUG
|
||||
#define FMT FORMAT
|
||||
#else
|
||||
#define FMT(...) (UNUSED(__VA_ARGS__), "")
|
||||
#endif
|
||||
|
||||
void serialize_bit_vector(std::ostream &out, const bit_vector &v);
|
||||
void deserialize_bit_vector(std::istream &in, bit_vector &v);
|
||||
|
||||
template<typename T>
|
||||
size_t size_in_bits(const std::vector<T> &v);
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
|
||||
|
||||
} // libsnark
|
||||
|
||||
#include "common/utils.tcc" /* note that utils has a templatized part (utils.tcc) and non-templatized part (utils.cpp) */
|
||||
#endif // UTILS_HPP_
|
||||
23
src/common/utils.tcc
Normal file
23
src/common/utils.tcc
Normal file
@@ -0,0 +1,23 @@
|
||||
/** @file
|
||||
*****************************************************************************
|
||||
Implementation of templatized utility functions
|
||||
*****************************************************************************
|
||||
* @author This file is part of libsnark, developed by SCIPR Lab
|
||||
* and contributors (see AUTHORS).
|
||||
* @copyright MIT license (see LICENSE file)
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef UTILS_TCC_
|
||||
#define UTILS_TCC_
|
||||
|
||||
namespace libsnark {
|
||||
|
||||
template<typename T>
|
||||
size_t size_in_bits(const std::vector<T> &v)
|
||||
{
|
||||
return v.size() * T::size_in_bits();
|
||||
}
|
||||
|
||||
} // libsnark
|
||||
|
||||
#endif // UTILS_TCC_
|
||||
Reference in New Issue
Block a user