Cleaner template usage, moved static functions out of CurveTrees class

This commit is contained in:
j-berman 2024-05-23 10:48:08 -07:00
parent 9ba00be519
commit 5ad026975a
6 changed files with 350 additions and 391 deletions

View File

@ -31,192 +31,22 @@
namespace fcmp
{
namespace curve_trees
{
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
using Helios = tower_cycle::Helios;
using Selene = tower_cycle::Selene;
// Instantiate the tower cycle types
template class CurveTrees<Helios, Selene>;
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
template<>
CurveTrees<Helios, Selene>::LeafTuple CurveTrees<Helios, Selene>::output_to_leaf_tuple(
const crypto::public_key &O,
const crypto::public_key &C) const
{
crypto::ec_point I;
crypto::derive_key_image_generator(O, I);
return LeafTuple{
.O_x = fcmp::tower_cycle::ed_25519_point_to_scalar(O),
.I_x = fcmp::tower_cycle::ed_25519_point_to_scalar(I),
.C_x = fcmp::tower_cycle::ed_25519_point_to_scalar(C)
};
};
// Public helper functions
//----------------------------------------------------------------------------------------------------------------------
template <typename C1, typename C2>
typename CurveTrees<C1, C2>::TreeExtension CurveTrees<C1, C2>::get_tree_extension(
const LastChunks &existing_last_chunks,
const std::vector<LeafTuple> &new_leaf_tuples)
{
TreeExtension tree_extension;
if (new_leaf_tuples.empty())
return tree_extension;
const auto &c1_last_chunks = existing_last_chunks.c1_last_chunks;
const auto &c2_last_chunks = existing_last_chunks.c2_last_chunks;
// Set the leaf start idx
tree_extension.leaves.start_idx = c2_last_chunks.empty()
? 0
: c2_last_chunks[0].child_layer_size;
// Copy the leaves
// TODO: don't copy here
tree_extension.leaves.tuples.reserve(new_leaf_tuples.size());
for (const auto &leaf : new_leaf_tuples)
{
tree_extension.leaves.tuples.emplace_back(LeafTuple{
.O_x = m_c2.clone(leaf.O_x),
.I_x = m_c2.clone(leaf.I_x),
.C_x = m_c2.clone(leaf.C_x)
});
}
auto &c1_layer_extensions_out = tree_extension.c1_layer_extensions;
auto &c2_layer_extensions_out = tree_extension.c2_layer_extensions;
const std::vector<typename C2::Scalar> flattened_leaves = this->flatten_leaves(new_leaf_tuples);
// Hash the leaf layer
LayerExtension<C2> leaf_parents;
this->hash_layer(m_c2,
c2_last_chunks.empty() ? nullptr : &c2_last_chunks[0],
flattened_leaves,
tree_extension.leaves.start_idx,
m_leaf_layer_chunk_width,
leaf_parents);
c2_layer_extensions_out.emplace_back(std::move(leaf_parents));
// Check if we just added the root
if (c2_layer_extensions_out.back().hashes.size() == 1 && c2_layer_extensions_out.back().start_idx == 0)
return tree_extension;
// Alternate between hashing c2 children, c1 children, c2, c1, ...
bool parent_is_c1 = true;
std::size_t c1_last_idx = 0;
std::size_t c2_last_idx = 0;
// TODO: calculate max number of layers it should take to add all leaves (existing leaves + new leaves)
while (true)
{
const LastChunkData<C1> *c1_last_chunk_ptr = (c1_last_chunks.size() <= c1_last_idx)
? nullptr
: &c1_last_chunks[c1_last_idx];
const LastChunkData<C2> *c2_last_chunk_ptr = (c2_last_chunks.size() <= c2_last_idx)
? nullptr
: &c2_last_chunks[c2_last_idx];
// TODO: templated function
if (parent_is_c1)
{
CHECK_AND_ASSERT_THROW_MES(c2_layer_extensions_out.size() > c2_last_idx, "missing c2 layer");
const auto &c2_child_extension = c2_layer_extensions_out[c2_last_idx];
const auto c1_child_scalars = this->next_child_scalars_from_children<C2, C1>(m_c2,
c2_last_chunk_ptr,
c1_last_chunk_ptr,
c2_child_extension);
LayerExtension<C1> c1_layer_extension;
this->hash_layer<C1>(m_c1,
c1_last_chunk_ptr,
c1_child_scalars,
c2_child_extension.start_idx,
m_c1_width,
c1_layer_extension);
c1_layer_extensions_out.emplace_back(std::move(c1_layer_extension));
// Check if we just added the root
if (c1_layer_extensions_out.back().hashes.size() == 1 && c1_layer_extensions_out.back().start_idx == 0)
return tree_extension;
++c2_last_idx;
}
else
{
CHECK_AND_ASSERT_THROW_MES(c1_layer_extensions_out.size() > c1_last_idx, "missing c1 layer");
const auto &c1_child_extension = c1_layer_extensions_out[c1_last_idx];
const auto c2_child_scalars = this->next_child_scalars_from_children<C1, C2>(m_c1,
c1_last_chunk_ptr,
c2_last_chunk_ptr,
c1_child_extension);
LayerExtension<C2> c2_layer_extension;
this->hash_layer<C2>(m_c2,
c2_last_chunk_ptr,
c2_child_scalars,
c1_child_extension.start_idx,
m_c2_width,
c2_layer_extension);
c2_layer_extensions_out.emplace_back(std::move(c2_layer_extension));
// Check if we just added the root
if (c2_layer_extensions_out.back().hashes.size() == 1 && c2_layer_extensions_out.back().start_idx == 0)
return tree_extension;
++c1_last_idx;
}
parent_is_c1 = !parent_is_c1;
}
};
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
// Private member functions
//----------------------------------------------------------------------------------------------------------------------
template <typename C1, typename C2>
std::vector<typename C2::Scalar> CurveTrees<C1, C2>::flatten_leaves(const std::vector<LeafTuple> &leaves) const
{
std::vector<typename C2::Scalar> flattened_leaves;
flattened_leaves.reserve(leaves.size() * LEAF_TUPLE_SIZE);
for (const auto &l : leaves)
{
// TODO: implement without cloning
flattened_leaves.emplace_back(m_c2.clone(l.O_x));
flattened_leaves.emplace_back(m_c2.clone(l.I_x));
flattened_leaves.emplace_back(m_c2.clone(l.C_x));
}
return flattened_leaves;
};
//----------------------------------------------------------------------------------------------------------------------
// Explicit instantiations
template Helios::Point CurveTrees<Helios, Selene>::get_new_parent(const Helios &curve,
const Helios::Chunk &new_children) const;
template Selene::Point CurveTrees<Helios, Selene>::get_new_parent(const Selene &curve,
const Selene::Chunk &new_children) const;
//----------------------------------------------------------------------------------------------------------------------
// Implementation
template <typename C1, typename C2>
template <typename C>
typename C::Point CurveTrees<C1, C2>::get_new_parent(const C &curve,
const typename C::Chunk &new_children) const
template<typename C>
typename C::Point get_new_parent(const C &curve, const typename C::Chunk &new_children)
{
// New parent means no prior children, fill priors with 0
std::vector<typename C::Scalar> prior_children;
fcmp::tower_cycle::extend_zeroes(curve, new_children.size(), prior_children);
tower_cycle::extend_zeroes(curve, new_children.size(), prior_children);
return curve.hash_grow(
curve.m_hash_init_point,
@ -227,34 +57,20 @@ typename C::Point CurveTrees<C1, C2>::get_new_parent(const C &curve,
};
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
// Explicit instantiations
template Helios::Point CurveTrees<Helios, Selene>::get_first_parent(const Helios &curve,
const Helios::Chunk &new_children,
const std::size_t chunk_width,
const bool child_layer_last_hash_updated,
const LastChunkData<Helios> *last_chunk_ptr,
const std::size_t offset) const;
template Selene::Point CurveTrees<Helios, Selene>::get_first_parent(const Selene &curve,
const Selene::Chunk &new_children,
const std::size_t chunk_width,
const bool child_layer_last_hash_updated,
const LastChunkData<Selene> *last_chunk_ptr,
const std::size_t offset) const;
// Static functions
//----------------------------------------------------------------------------------------------------------------------
// Implementation
template <typename C1, typename C2>
template <typename C>
typename C::Point CurveTrees<C1, C2>::get_first_parent(const C &curve,
// Hash the first chunk of children being added to a layer
template<typename C>
static typename C::Point get_first_parent(const C &curve,
const typename C::Chunk &new_children,
const std::size_t chunk_width,
const bool child_layer_last_hash_updated,
const LastChunkData<C> *last_chunk_ptr,
const std::size_t offset) const
const std::size_t offset)
{
// If no last chunk exists, we can get a new parent
if (last_chunk_ptr == nullptr)
return this->get_new_parent<C>(curve, new_children);
return get_new_parent<C>(curve, new_children);
std::vector<typename C::Scalar> prior_children;
@ -265,18 +81,18 @@ typename C::Point CurveTrees<C1, C2>::get_first_parent(const C &curve,
// Extend prior children by zeroes for any additional new children, since they must be new
if (new_children.size() > 1)
fcmp::tower_cycle::extend_zeroes(curve, new_children.size() - 1, prior_children);
tower_cycle::extend_zeroes(curve, new_children.size() - 1, prior_children);
}
else if (offset > 0)
{
// If we're updating the parent hash and no children were updated, then we're just adding new children
// to the existing last chunk and can fill priors with 0
fcmp::tower_cycle::extend_zeroes(curve, new_children.size(), prior_children);
tower_cycle::extend_zeroes(curve, new_children.size(), prior_children);
}
else
{
// If the last chunk is already full and isn't updated in any way, then we just get a new parent
return this->get_new_parent<C>(curve, new_children);
return get_new_parent<C>(curve, new_children);
}
return curve.hash_grow(
@ -287,22 +103,10 @@ typename C::Point CurveTrees<C1, C2>::get_first_parent(const C &curve,
);
};
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
// Explicit instantiations
template std::vector<Helios::Scalar> CurveTrees<Helios, Selene>::next_child_scalars_from_children(const Selene &c_child,
const LastChunkData<Selene> *last_child_chunk_ptr,
const LastChunkData<Helios> *last_parent_chunk_ptr,
const LayerExtension<Selene> &children);
template std::vector<Selene::Scalar> CurveTrees<Helios, Selene>::next_child_scalars_from_children(const Helios &c_child,
const LastChunkData<Helios> *last_child_chunk_ptr,
const LastChunkData<Selene> *last_parent_chunk_ptr,
const LayerExtension<Helios> &children);
//----------------------------------------------------------------------------------------------------------------------
// Implementation
template <typename C1, typename C2>
// After hashing a layer of children points, convert those children x-coordinates into their respective cycle
// scalars, and prepare them to be hashed for the next layer
template<typename C_CHILD, typename C_PARENT>
std::vector<typename C_PARENT::Scalar> CurveTrees<C1, C2>::next_child_scalars_from_children(const C_CHILD &c_child,
static std::vector<typename C_PARENT::Scalar> next_child_scalars_from_children(const C_CHILD &c_child,
const LastChunkData<C_CHILD> *last_child_chunk_ptr,
const LastChunkData<C_PARENT> *last_parent_chunk_ptr,
const LayerExtension<C_CHILD> &children)
@ -333,26 +137,9 @@ std::vector<typename C_PARENT::Scalar> CurveTrees<C1, C2>::next_child_scalars_fr
return child_scalars;
};
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
// Explicit instantiations
template void CurveTrees<Helios, Selene>::hash_layer(const Helios &curve,
const LastChunkData<Helios> *last_parent_chunk_ptr,
const std::vector<Helios::Scalar> &child_scalars,
const std::size_t children_start_idx,
const std::size_t chunk_width,
LayerExtension<Helios> &parents_out);
template void CurveTrees<Helios, Selene>::hash_layer(const Selene &curve,
const LastChunkData<Selene> *last_parent_chunk_ptr,
const std::vector<Selene::Scalar> &child_scalars,
const std::size_t children_start_idx,
const std::size_t chunk_width,
LayerExtension<Selene> &parents_out);
//----------------------------------------------------------------------------------------------------------------------
// Implementation
template <typename C1, typename C2>
// Hash chunks of a layer of new children, outputting the next layer's parents
template<typename C>
void CurveTrees<C1, C2>::hash_layer(const C &curve,
static void hash_layer(const C &curve,
const LastChunkData<C> *last_parent_chunk_ptr,
const std::vector<typename C::Scalar> &child_scalars,
const std::size_t children_start_idx,
@ -415,7 +202,7 @@ void CurveTrees<C1, C2>::hash_layer(const C &curve,
child_layer_last_hash_updated,
last_parent_chunk_ptr,
offset)
: this->get_new_parent<C>(curve, chunk);
: get_new_parent<C>(curve, chunk);
MDEBUG("Hash chunk_start_idx " << chunk_start_idx << " result: " << curve.to_string(chunk_hash)
<< " , chunk_size: " << chunk_size);
@ -437,4 +224,169 @@ void CurveTrees<C1, C2>::hash_layer(const C &curve,
};
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
// CurveTrees public member functions
//----------------------------------------------------------------------------------------------------------------------
template<>
CurveTrees<Helios, Selene>::LeafTuple CurveTrees<Helios, Selene>::output_to_leaf_tuple(
const crypto::public_key &O,
const crypto::public_key &C) const
{
crypto::ec_point I;
crypto::derive_key_image_generator(O, I);
return LeafTuple{
.O_x = tower_cycle::ed_25519_point_to_scalar(O),
.I_x = tower_cycle::ed_25519_point_to_scalar(I),
.C_x = tower_cycle::ed_25519_point_to_scalar(C)
};
};
//----------------------------------------------------------------------------------------------------------------------
template<typename C1, typename C2>
typename CurveTrees<C1, C2>::TreeExtension CurveTrees<C1, C2>::get_tree_extension(
const LastChunks &existing_last_chunks,
const std::vector<LeafTuple> &new_leaf_tuples)
{
TreeExtension tree_extension;
if (new_leaf_tuples.empty())
return tree_extension;
const auto &c1_last_chunks = existing_last_chunks.c1_last_chunks;
const auto &c2_last_chunks = existing_last_chunks.c2_last_chunks;
// Set the leaf start idx
tree_extension.leaves.start_idx = c2_last_chunks.empty()
? 0
: c2_last_chunks[0].child_layer_size;
// Copy the leaves
// TODO: don't copy here
tree_extension.leaves.tuples.reserve(new_leaf_tuples.size());
for (const auto &leaf : new_leaf_tuples)
{
tree_extension.leaves.tuples.emplace_back(LeafTuple{
.O_x = m_c2.clone(leaf.O_x),
.I_x = m_c2.clone(leaf.I_x),
.C_x = m_c2.clone(leaf.C_x)
});
}
auto &c1_layer_extensions_out = tree_extension.c1_layer_extensions;
auto &c2_layer_extensions_out = tree_extension.c2_layer_extensions;
const std::vector<typename C2::Scalar> flattened_leaves = this->flatten_leaves(new_leaf_tuples);
// Hash the leaf layer
LayerExtension<C2> leaf_parents;
hash_layer(m_c2,
c2_last_chunks.empty() ? nullptr : &c2_last_chunks[0],
flattened_leaves,
tree_extension.leaves.start_idx,
m_leaf_layer_chunk_width,
leaf_parents);
c2_layer_extensions_out.emplace_back(std::move(leaf_parents));
// Check if we just added the root
if (c2_layer_extensions_out.back().hashes.size() == 1 && c2_layer_extensions_out.back().start_idx == 0)
return tree_extension;
// Alternate between hashing c2 children, c1 children, c2, c1, ...
bool parent_is_c1 = true;
std::size_t c1_last_idx = 0;
std::size_t c2_last_idx = 0;
// TODO: calculate max number of layers it should take to add all leaves (existing leaves + new leaves)
while (true)
{
const LastChunkData<C1> *c1_last_chunk_ptr = (c1_last_chunks.size() <= c1_last_idx)
? nullptr
: &c1_last_chunks[c1_last_idx];
const LastChunkData<C2> *c2_last_chunk_ptr = (c2_last_chunks.size() <= c2_last_idx)
? nullptr
: &c2_last_chunks[c2_last_idx];
// TODO: templated function
if (parent_is_c1)
{
CHECK_AND_ASSERT_THROW_MES(c2_layer_extensions_out.size() > c2_last_idx, "missing c2 layer");
const auto &c2_child_extension = c2_layer_extensions_out[c2_last_idx];
const auto c1_child_scalars = next_child_scalars_from_children<C2, C1>(m_c2,
c2_last_chunk_ptr,
c1_last_chunk_ptr,
c2_child_extension);
LayerExtension<C1> c1_layer_extension;
hash_layer<C1>(m_c1,
c1_last_chunk_ptr,
c1_child_scalars,
c2_child_extension.start_idx,
m_c1_width,
c1_layer_extension);
c1_layer_extensions_out.emplace_back(std::move(c1_layer_extension));
// Check if we just added the root
if (c1_layer_extensions_out.back().hashes.size() == 1 && c1_layer_extensions_out.back().start_idx == 0)
return tree_extension;
++c2_last_idx;
}
else
{
CHECK_AND_ASSERT_THROW_MES(c1_layer_extensions_out.size() > c1_last_idx, "missing c1 layer");
const auto &c1_child_extension = c1_layer_extensions_out[c1_last_idx];
const auto c2_child_scalars = next_child_scalars_from_children<C1, C2>(m_c1,
c1_last_chunk_ptr,
c2_last_chunk_ptr,
c1_child_extension);
LayerExtension<C2> c2_layer_extension;
hash_layer<C2>(m_c2,
c2_last_chunk_ptr,
c2_child_scalars,
c1_child_extension.start_idx,
m_c2_width,
c2_layer_extension);
c2_layer_extensions_out.emplace_back(std::move(c2_layer_extension));
// Check if we just added the root
if (c2_layer_extensions_out.back().hashes.size() == 1 && c2_layer_extensions_out.back().start_idx == 0)
return tree_extension;
++c1_last_idx;
}
parent_is_c1 = !parent_is_c1;
}
};
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
// CurveTrees private member functions
//----------------------------------------------------------------------------------------------------------------------
template<typename C1, typename C2>
std::vector<typename C2::Scalar> CurveTrees<C1, C2>::flatten_leaves(const std::vector<LeafTuple> &leaves) const
{
std::vector<typename C2::Scalar> flattened_leaves;
flattened_leaves.reserve(leaves.size() * LEAF_TUPLE_SIZE);
for (const auto &l : leaves)
{
// TODO: implement without cloning
flattened_leaves.emplace_back(m_c2.clone(l.O_x));
flattened_leaves.emplace_back(m_c2.clone(l.I_x));
flattened_leaves.emplace_back(m_c2.clone(l.C_x));
}
return flattened_leaves;
};
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
} //namespace curve_trees
} //namespace fcmp

View File

@ -37,10 +37,45 @@
// forward declarations
class CurveTreesUnitTest;
namespace fcmp
{
namespace curve_trees
{
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
// Hash a chunk of new children
template<typename C>
typename C::Point get_new_parent(const C &curve, const typename C::Chunk &new_children);
//----------------------------------------------------------------------------------------------------------------------
// A layer of contiguous hashes starting from a specific start_idx in the tree
template<typename C>
struct LayerExtension final
{
std::size_t start_idx;
std::vector<typename C::Point> hashes;
};
// TODO: longer descriptions
// Useful data from the last chunk in a layer
template<typename C>
struct LastChunkData final
{
// The total number of children % child layer chunk width
const std::size_t child_offset;
// The last child in the chunk (and therefore the last child in the child layer)
/* TODO: const */ typename C::Scalar last_child;
// The hash of the last chunk of child scalars
/* TODO: const */ typename C::Point last_parent;
// Total number of children in the child layer
const std::size_t child_layer_size;
// Total number of hashes in the parent layer
const std::size_t parent_layer_size;
};
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
// This class is useful help update the curve trees tree without needing to keep the entire tree in memory
// - It requires instantiation with the C1 and C2 curve classes and widths, hardening the tree structure
// - It ties the C2 curve in the tree to the leaf layer
template<typename C1, typename C2>
class CurveTrees
{
@ -72,7 +107,7 @@ public:
static const std::size_t LEAF_TUPLE_SIZE = 3;
static_assert(sizeof(LeafTuple) == (sizeof(typename C2::Scalar) * LEAF_TUPLE_SIZE), "unexpected LeafTuple size");
// Leaves in the tree
// Contiguous leaves in the tree, starting a specified start_idx in the leaf layer
struct Leaves final
{
// Starting index in the leaf layer
@ -81,14 +116,6 @@ public:
std::vector<LeafTuple> tuples;
};
// A layer of contiguous hashes starting from a specific start_idx in the tree
template<typename C>
struct LayerExtension final
{
std::size_t start_idx;
std::vector<typename C::Point> hashes;
};
// A struct useful to extend an existing tree
// - layers alternate between C1 and C2
// - c2_layer_extensions[0] is first layer after leaves, then c1_layer_extensions[0], c2_layer_extensions[1], etc
@ -99,22 +126,6 @@ public:
std::vector<LayerExtension<C2>> c2_layer_extensions;
};
// Useful data from the last chunk in a layer
template<typename C>
struct LastChunkData final
{
// The total number of children % child layer chunk width
/*TODO: const*/ std::size_t child_offset;
// The last child in the chunk (and therefore the last child in the child layer)
/*TODO: const*/ typename C::Scalar last_child;
// The hash of the last chunk of child scalars
/*TODO: const*/ typename C::Point last_parent;
// Total number of children in the child layer
/*TODO: const*/ std::size_t child_layer_size;
// Total number of hashes in the parent layer
/*TODO: const*/ std::size_t parent_layer_size;
};
// Last chunk data from each layer in the tree
// - layers alternate between C1 and C2
// - c2_last_chunks[0] is first layer after leaves, then c1_last_chunks[0], then c2_last_chunks[1], etc
@ -139,46 +150,24 @@ private:
// Flatten leaves [(O.x, I.x, C.x),(O.x, I.x, C.x),...] -> [scalar,scalar,scalar,scalar,scalar,scalar,...]
std::vector<typename C2::Scalar> flatten_leaves(const std::vector<LeafTuple> &leaves) const;
// TODO: make below functions static functions inside curve_trees.cpp
// Hash a chunk of new children
template <typename C>
typename C::Point get_new_parent(const C &curve, const typename C::Chunk &new_children) const;
// Hash the first chunk of children being added to a layer
template <typename C>
typename C::Point get_first_parent(const C &curve,
const typename C::Chunk &new_children,
const std::size_t chunk_width,
const bool child_layer_last_hash_updated,
const LastChunkData<C> *last_chunk_ptr,
const std::size_t offset) const;
// After hashing a layer of children points, convert those children x-coordinates into their respective cycle
// scalars, and prepare them to be hashed for the next layer
template<typename C_CHILD, typename C_PARENT>
std::vector<typename C_PARENT::Scalar> next_child_scalars_from_children(const C_CHILD &c_child,
const LastChunkData<C_CHILD> *last_child_chunk_ptr,
const LastChunkData<C_PARENT> *last_parent_chunk_ptr,
const LayerExtension<C_CHILD> &children);
// Hash chunks of a layer of new children, outputting the next layer's parents
template<typename C>
void hash_layer(const C &curve,
const LastChunkData<C> *last_parent_chunk_ptr,
const std::vector<typename C::Scalar> &child_scalars,
const std::size_t children_start_idx,
const std::size_t chunk_width,
LayerExtension<C> &parents_out);
//member variables
private:
// The curves
const C1 &m_c1;
const C2 &m_c2;
// The chunk widths of the layers in the tree tied to each curve
const std::size_t m_c1_width;
const std::size_t m_c2_width;
// The leaf layer has a distinct chunk width than the other layers
const std::size_t m_leaf_layer_chunk_width;
};
//----------------------------------------------------------------------------------------------------------------------
using Helios = tower_cycle::Helios;
using Selene = tower_cycle::Selene;
using CurveTreesV1 = CurveTrees<Helios, Selene>;
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
} //namespace curve_trees
} //namespace fcmp

View File

@ -144,16 +144,7 @@ std::string Selene::to_string(const typename Selene::Point &point) const
}
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
SeleneScalar ed_25519_point_to_scalar(const crypto::ec_point &point)
{
static_assert(sizeof(RustEd25519Point) == sizeof(crypto::ec_point),
"expected same size ed25519 point to rust representation");
// TODO: implement reading just the x coordinate of ed25519 point in C/C++
fcmp::tower_cycle::RustEd25519Point rust_point;
memcpy(&rust_point, &point, sizeof(fcmp::tower_cycle::RustEd25519Point));
return fcmp_rust::ed25519_point_to_selene_scalar(rust_point);
}
// Exposed helper functions
//----------------------------------------------------------------------------------------------------------------------
Helios::Generators random_helios_generators(std::size_t n)
{
@ -175,6 +166,61 @@ Selene::Point random_selene_hash_init_point()
return fcmp_rust::random_selene_hash_init_point();
}
//----------------------------------------------------------------------------------------------------------------------
SeleneScalar ed_25519_point_to_scalar(const crypto::ec_point &point)
{
static_assert(sizeof(RustEd25519Point) == sizeof(crypto::ec_point),
"expected same size ed25519 point to rust representation");
// TODO: implement reading just the x coordinate of ed25519 point in C/C++
fcmp::tower_cycle::RustEd25519Point rust_point;
memcpy(&rust_point, &point, sizeof(fcmp::tower_cycle::RustEd25519Point));
return fcmp_rust::ed25519_point_to_selene_scalar(rust_point);
}
//----------------------------------------------------------------------------------------------------------------------
template<typename C>
void extend_zeroes(const C &curve,
const std::size_t num_zeroes,
std::vector<typename C::Scalar> &zeroes_inout)
{
zeroes_inout.reserve(zeroes_inout.size() + num_zeroes);
for (std::size_t i = 0; i < num_zeroes; ++i)
zeroes_inout.emplace_back(curve.zero_scalar());
}
// Explicit instantiations
template void extend_zeroes<Helios>(const Helios &curve,
const std::size_t num_zeroes,
std::vector<Helios::Scalar> &zeroes_inout);
template void extend_zeroes<Selene>(const Selene &curve,
const std::size_t num_zeroes,
std::vector<Selene::Scalar> &zeroes_inout);
//----------------------------------------------------------------------------------------------------------------------
template<typename C_POINTS, typename C_SCALARS>
void extend_scalars_from_cycle_points(const C_POINTS &curve,
const std::vector<typename C_POINTS::Point> &points,
std::vector<typename C_SCALARS::Scalar> &scalars_out)
{
scalars_out.reserve(scalars_out.size() + points.size());
for (const auto &point : points)
{
// TODO: implement reading just the x coordinate of points on curves in curve cycle in C/C++
typename C_SCALARS::Scalar scalar = curve.point_to_cycle_scalar(point);
scalars_out.push_back(std::move(scalar));
}
}
// Explicit instantiations
template void extend_scalars_from_cycle_points<Helios, Selene>(const Helios &curve,
const std::vector<Helios::Point> &points,
std::vector<Selene::Scalar> &scalars_out);
template void extend_scalars_from_cycle_points<Selene, Helios>(const Selene &curve,
const std::vector<Selene::Point> &points,
std::vector<Helios::Scalar> &scalars_out);
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
} //namespace tower_cycle
} //namespace fcmp

View File

@ -67,8 +67,7 @@ struct SeleneT final
};
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
// Parent curve class that curves in a cycle must implement
//----------------------------------------------------------------------------------------------------------------------
// Abstract parent curve class that curves in a cycle must implement
template<typename C>
class Curve
{
@ -185,9 +184,6 @@ public:
};
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
// Ed25519 point x-coordinates are Selene scalars
SeleneScalar ed_25519_point_to_scalar(const crypto::ec_point &point);
//----------------------------------------------------------------------------------------------------------------------
// TODO: use static constants and get rid of the below functions (WARNING: number of generators must be >= curve's
// width, and also need to account for selene leaf layer 3x)
Helios::Generators random_helios_generators(std::size_t n);
@ -195,35 +191,19 @@ Selene::Generators random_selene_generators(std::size_t n);
Helios::Point random_helios_hash_init_point();
Selene::Point random_selene_hash_init_point();
//----------------------------------------------------------------------------------------------------------------------
// Ed25519 point x-coordinates are Selene scalars
SeleneScalar ed_25519_point_to_scalar(const crypto::ec_point &point);
//----------------------------------------------------------------------------------------------------------------------
// TODO: implement in cpp file
template <typename C>
static void extend_zeroes(const C &curve,
template<typename C>
void extend_zeroes(const C &curve,
const std::size_t num_zeroes,
std::vector<typename C::Scalar> &zeroes_inout)
{
zeroes_inout.reserve(zeroes_inout.size() + num_zeroes);
for (std::size_t i = 0; i < num_zeroes; ++i)
zeroes_inout.emplace_back(curve.zero_scalar());
}
std::vector<typename C::Scalar> &zeroes_inout);
//----------------------------------------------------------------------------------------------------------------------
// TODO: move impl into cpp
template <typename C_POINTS, typename C_SCALARS>
static void extend_scalars_from_cycle_points(const C_POINTS &curve,
template<typename C_POINTS, typename C_SCALARS>
void extend_scalars_from_cycle_points(const C_POINTS &curve,
const std::vector<typename C_POINTS::Point> &points,
std::vector<typename C_SCALARS::Scalar> &scalars_out)
{
scalars_out.reserve(scalars_out.size() + points.size());
for (const auto &point : points)
{
// TODO: implement reading just the x coordinate of points on curves in curve cycle in C/C++
typename C_SCALARS::Scalar scalar = curve.point_to_cycle_scalar(point);
scalars_out.push_back(std::move(scalar));
}
}
std::vector<typename C_SCALARS::Scalar> &scalars_out);
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
}//namespace curves
}//namespace tower_cycle
}//namespace fcmp

View File

@ -35,7 +35,7 @@
// CurveTreesUnitTest helpers
//----------------------------------------------------------------------------------------------------------------------
template<typename C>
static CurveTreesV1::LastChunkData<C> get_last_child_layer_chunk(const C &curve,
static fcmp::curve_trees::LastChunkData<C> get_last_child_layer_chunk(const C &curve,
const std::size_t child_layer_size,
const std::size_t parent_layer_size,
const std::size_t chunk_width,
@ -47,7 +47,7 @@ static CurveTreesV1::LastChunkData<C> get_last_child_layer_chunk(const C &curve,
const std::size_t child_offset = child_layer_size % chunk_width;
return CurveTreesV1::LastChunkData<C>{
return fcmp::curve_trees::LastChunkData<C>{
.child_offset = child_offset,
.last_child = curve.clone(last_child),
.last_parent = curve.clone(last_parent),
@ -56,6 +56,39 @@ static CurveTreesV1::LastChunkData<C> get_last_child_layer_chunk(const C &curve,
};
}
//----------------------------------------------------------------------------------------------------------------------
template<typename C_PARENT>
static bool validate_layer(const C_PARENT &c_parent,
const CurveTreesUnitTest::Layer<C_PARENT> &parents,
const std::vector<typename C_PARENT::Scalar> &child_scalars,
const std::size_t max_chunk_size)
{
// Hash chunk of children scalars, then see if the hash matches up to respective parent
std::size_t chunk_start_idx = 0;
for (std::size_t i = 0; i < parents.size(); ++i)
{
CHECK_AND_ASSERT_MES(child_scalars.size() > chunk_start_idx, false, "chunk start too high");
const std::size_t chunk_size = std::min(child_scalars.size() - chunk_start_idx, max_chunk_size);
CHECK_AND_ASSERT_MES(child_scalars.size() >= (chunk_start_idx + chunk_size), false, "chunk size too large");
const typename C_PARENT::Point &parent = parents[i];
const auto chunk_start = child_scalars.data() + chunk_start_idx;
const typename C_PARENT::Chunk chunk{chunk_start, chunk_size};
const typename C_PARENT::Point chunk_hash = fcmp::curve_trees::get_new_parent(c_parent, chunk);
const auto actual_bytes = c_parent.to_bytes(parent);
const auto expected_bytes = c_parent.to_bytes(chunk_hash);
CHECK_AND_ASSERT_MES(actual_bytes == expected_bytes, false, "unexpected hash");
chunk_start_idx += chunk_size;
}
CHECK_AND_ASSERT_THROW_MES(chunk_start_idx == child_scalars.size(), "unexpected ending chunk start idx");
return true;
}
//----------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------
// CurveTreesUnitTest implementations
//----------------------------------------------------------------------------------------------------------------------
@ -191,7 +224,7 @@ void CurveTreesUnitTest::extend_tree(const CurveTreesV1::TreeExtension &tree_ext
if (use_c2)
{
CHECK_AND_ASSERT_THROW_MES(c2_idx < c2_extensions.size(), "unexpected c2 layer extension");
const CurveTreesV1::LayerExtension<Selene> &c2_ext = c2_extensions[c2_idx];
const fcmp::curve_trees::LayerExtension<Selene> &c2_ext = c2_extensions[c2_idx];
CHECK_AND_ASSERT_THROW_MES(!c2_ext.hashes.empty(), "empty c2 layer extension");
@ -217,7 +250,7 @@ void CurveTreesUnitTest::extend_tree(const CurveTreesV1::TreeExtension &tree_ext
else
{
CHECK_AND_ASSERT_THROW_MES(c1_idx < c1_extensions.size(), "unexpected c1 layer extension");
const CurveTreesV1::LayerExtension<Helios> &c1_ext = c1_extensions[c1_idx];
const fcmp::curve_trees::LayerExtension<Helios> &c1_ext = c1_extensions[c1_idx];
CHECK_AND_ASSERT_THROW_MES(!c1_ext.hashes.empty(), "empty c1 layer extension");
@ -245,39 +278,6 @@ void CurveTreesUnitTest::extend_tree(const CurveTreesV1::TreeExtension &tree_ext
}
}
//----------------------------------------------------------------------------------------------------------------------
template<typename C_PARENT>
bool CurveTreesUnitTest::validate_layer(const C_PARENT &c_parent,
const CurveTreesUnitTest::Layer<C_PARENT> &parents,
const std::vector<typename C_PARENT::Scalar> &child_scalars,
const std::size_t max_chunk_size)
{
// Hash chunk of children scalars, then see if the hash matches up to respective parent
std::size_t chunk_start_idx = 0;
for (std::size_t i = 0; i < parents.size(); ++i)
{
CHECK_AND_ASSERT_MES(child_scalars.size() > chunk_start_idx, false, "chunk start too high");
const std::size_t chunk_size = std::min(child_scalars.size() - chunk_start_idx, max_chunk_size);
CHECK_AND_ASSERT_MES(child_scalars.size() >= (chunk_start_idx + chunk_size), false, "chunk size too large");
const typename C_PARENT::Point &parent = parents[i];
const auto chunk_start = child_scalars.data() + chunk_start_idx;
const typename C_PARENT::Chunk chunk{chunk_start, chunk_size};
const typename C_PARENT::Point chunk_hash = m_curve_trees.get_new_parent(c_parent, chunk);
const auto actual_bytes = c_parent.to_bytes(parent);
const auto expected_bytes = c_parent.to_bytes(chunk_hash);
CHECK_AND_ASSERT_MES(actual_bytes == expected_bytes, false, "unexpected hash");
chunk_start_idx += chunk_size;
}
CHECK_AND_ASSERT_THROW_MES(chunk_start_idx == child_scalars.size(), "unexpected ending chunk start idx");
return true;
}
//----------------------------------------------------------------------------------------------------------------------
bool CurveTreesUnitTest::validate_tree(const CurveTreesUnitTest::Tree &tree)
{
const auto &leaves = tree.leaves;
@ -317,7 +317,7 @@ bool CurveTreesUnitTest::validate_tree(const CurveTreesUnitTest::Tree &tree)
children,
child_scalars);
const bool valid = this->validate_layer<Selene>(m_curve_trees.m_c2,
const bool valid = validate_layer<Selene>(m_curve_trees.m_c2,
parents,
child_scalars,
m_curve_trees.m_c2_width);
@ -342,7 +342,7 @@ bool CurveTreesUnitTest::validate_tree(const CurveTreesUnitTest::Tree &tree)
children,
child_scalars);
const bool valid = this->validate_layer<Helios>(
const bool valid = validate_layer<Helios>(
m_curve_trees.m_c1,
parents,
child_scalars,
@ -357,7 +357,7 @@ bool CurveTreesUnitTest::validate_tree(const CurveTreesUnitTest::Tree &tree)
}
// Now validate leaves
return this->validate_layer<Selene>(m_curve_trees.m_c2,
return validate_layer<Selene>(m_curve_trees.m_c2,
c2_layers[0],
m_curve_trees.flatten_leaves(leaves),
m_curve_trees.m_leaf_layer_chunk_width);
@ -382,7 +382,7 @@ void CurveTreesUnitTest::log_last_chunks(const CurveTreesV1::LastChunks &last_ch
{
CHECK_AND_ASSERT_THROW_MES(c2_idx < c2_last_chunks.size(), "unexpected c2 layer");
const CurveTreesV1::LastChunkData<Selene> &last_chunk = c2_last_chunks[c2_idx];
const fcmp::curve_trees::LastChunkData<Selene> &last_chunk = c2_last_chunks[c2_idx];
MDEBUG("child_offset: " << last_chunk.child_offset
<< " , last_child: " << m_curve_trees.m_c2.to_string(last_chunk.last_child)
@ -396,7 +396,7 @@ void CurveTreesUnitTest::log_last_chunks(const CurveTreesV1::LastChunks &last_ch
{
CHECK_AND_ASSERT_THROW_MES(c1_idx < c1_last_chunks.size(), "unexpected c1 layer");
const CurveTreesV1::LastChunkData<Helios> &last_chunk = c1_last_chunks[c1_idx];
const fcmp::curve_trees::LastChunkData<Helios> &last_chunk = c1_last_chunks[c1_idx];
MDEBUG("child_offset: " << last_chunk.child_offset
<< " , last_child: " << m_curve_trees.m_c1.to_string(last_chunk.last_child)
@ -441,7 +441,7 @@ void CurveTreesUnitTest::log_tree_extension(const CurveTreesV1::TreeExtension &t
{
CHECK_AND_ASSERT_THROW_MES(c2_idx < c2_extensions.size(), "unexpected c2 layer");
const CurveTreesV1::LayerExtension<Selene> &c2_layer = c2_extensions[c2_idx];
const fcmp::curve_trees::LayerExtension<Selene> &c2_layer = c2_extensions[c2_idx];
MDEBUG("Selene tree extension start idx: " << c2_layer.start_idx);
for (std::size_t j = 0; j < c2_layer.hashes.size(); ++j)
@ -454,7 +454,7 @@ void CurveTreesUnitTest::log_tree_extension(const CurveTreesV1::TreeExtension &t
{
CHECK_AND_ASSERT_THROW_MES(c1_idx < c1_extensions.size(), "unexpected c1 layer");
const CurveTreesV1::LayerExtension<Helios> &c1_layer = c1_extensions[c1_idx];
const fcmp::curve_trees::LayerExtension<Helios> &c1_layer = c1_extensions[c1_idx];
MDEBUG("Helios tree extension start idx: " << c1_layer.start_idx);
for (std::size_t j = 0; j < c1_layer.hashes.size(); ++j)
@ -582,7 +582,7 @@ static void grow_tree_test(Helios &helios,
helios_width,
selene_width);
CurveTreesUnitTest curve_trees_accesor{curve_trees};
CurveTreesUnitTest curve_trees_accessor{curve_trees};
CHECK_AND_ASSERT_THROW_MES(helios_width > 1, "helios width must be > 1");
CHECK_AND_ASSERT_THROW_MES(selene_width > 1, "selene width must be > 1");
@ -629,7 +629,7 @@ static void grow_tree_test(Helios &helios,
MDEBUG("Adding " << init_leaves << " leaves to tree");
grow_tree(curve_trees,
curve_trees_accesor,
curve_trees_accessor,
init_leaves,
global_tree);
@ -639,7 +639,7 @@ static void grow_tree_test(Helios &helios,
MDEBUG("Extending tree by " << ext_leaves << " leaves");
grow_tree(curve_trees,
curve_trees_accesor,
curve_trees_accessor,
ext_leaves,
global_tree);

View File

@ -32,11 +32,11 @@
#include "fcmp/tower_cycle.h"
#include "misc_log_ex.h"
using Helios = fcmp::tower_cycle::Helios;
using Selene = fcmp::tower_cycle::Selene;
using CurveTreesV1 = fcmp::CurveTrees<Helios, Selene>;
using Helios = fcmp::curve_trees::Helios;
using Selene = fcmp::curve_trees::Selene;
using CurveTreesV1 = fcmp::curve_trees::CurveTreesV1;
// Helper class that can access the private members of the CurveTrees class
class CurveTreesUnitTest
{
public:
@ -71,14 +71,6 @@ public:
void log_tree_extension(const CurveTreesV1::TreeExtension &tree_extension);
void log_tree(const CurveTreesUnitTest::Tree &tree);
//private member functions
private:
template<typename C_PARENT>
bool validate_layer(const C_PARENT &c_parent,
const Layer<C_PARENT> &parents,
const std::vector<typename C_PARENT::Scalar> &child_scalars,
const std::size_t max_chunk_size);
private:
CurveTreesV1 &m_curve_trees;
};