diff --git a/src/fcmp/curve_trees.cpp b/src/fcmp/curve_trees.cpp index 0ad0c1aed..3399d8146 100644 --- a/src/fcmp/curve_trees.cpp +++ b/src/fcmp/curve_trees.cpp @@ -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; //---------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------- -template<> -CurveTrees::LeafTuple CurveTrees::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 CurveTrees::TreeExtension CurveTrees::get_tree_extension( - const LastChunks &existing_last_chunks, - const std::vector &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 flattened_leaves = this->flatten_leaves(new_leaf_tuples); - - // Hash the leaf layer - LayerExtension 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_last_chunk_ptr = (c1_last_chunks.size() <= c1_last_idx) - ? nullptr - : &c1_last_chunks[c1_last_idx]; - - const LastChunkData *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(m_c2, - c2_last_chunk_ptr, - c1_last_chunk_ptr, - c2_child_extension); - - LayerExtension c1_layer_extension; - this->hash_layer(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(m_c1, - c1_last_chunk_ptr, - c2_last_chunk_ptr, - c1_child_extension); - - LayerExtension c2_layer_extension; - this->hash_layer(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 -std::vector CurveTrees::flatten_leaves(const std::vector &leaves) const -{ - std::vector 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::get_new_parent(const Helios &curve, - const Helios::Chunk &new_children) const; - -template Selene::Point CurveTrees::get_new_parent(const Selene &curve, - const Selene::Chunk &new_children) const; -//---------------------------------------------------------------------------------------------------------------------- -// Implementation -template -template -typename C::Point CurveTrees::get_new_parent(const C &curve, - const typename C::Chunk &new_children) const +template +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 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::get_new_parent(const C &curve, }; //---------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------- -// Explicit instantiations -template Helios::Point CurveTrees::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 *last_chunk_ptr, - const std::size_t offset) const; - -template Selene::Point CurveTrees::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 *last_chunk_ptr, - const std::size_t offset) const; +// Static functions //---------------------------------------------------------------------------------------------------------------------- -// Implementation -template -template -typename C::Point CurveTrees::get_first_parent(const C &curve, +// Hash the first chunk of children being added to a layer +template +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 *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(curve, new_children); + return get_new_parent(curve, new_children); std::vector prior_children; @@ -265,18 +81,18 @@ typename C::Point CurveTrees::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(curve, new_children); + return get_new_parent(curve, new_children); } return curve.hash_grow( @@ -287,22 +103,10 @@ typename C::Point CurveTrees::get_first_parent(const C &curve, ); }; //---------------------------------------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------------------------------------- -// Explicit instantiations -template std::vector CurveTrees::next_child_scalars_from_children(const Selene &c_child, - const LastChunkData *last_child_chunk_ptr, - const LastChunkData *last_parent_chunk_ptr, - const LayerExtension &children); - -template std::vector CurveTrees::next_child_scalars_from_children(const Helios &c_child, - const LastChunkData *last_child_chunk_ptr, - const LastChunkData *last_parent_chunk_ptr, - const LayerExtension &children); -//---------------------------------------------------------------------------------------------------------------------- -// Implementation -template +// 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 -std::vector CurveTrees::next_child_scalars_from_children(const C_CHILD &c_child, +static std::vector next_child_scalars_from_children(const C_CHILD &c_child, const LastChunkData *last_child_chunk_ptr, const LastChunkData *last_parent_chunk_ptr, const LayerExtension &children) @@ -333,26 +137,9 @@ std::vector CurveTrees::next_child_scalars_fr return child_scalars; }; //---------------------------------------------------------------------------------------------------------------------- -//---------------------------------------------------------------------------------------------------------------------- -// Explicit instantiations -template void CurveTrees::hash_layer(const Helios &curve, - const LastChunkData *last_parent_chunk_ptr, - const std::vector &child_scalars, - const std::size_t children_start_idx, - const std::size_t chunk_width, - LayerExtension &parents_out); - -template void CurveTrees::hash_layer(const Selene &curve, - const LastChunkData *last_parent_chunk_ptr, - const std::vector &child_scalars, - const std::size_t children_start_idx, - const std::size_t chunk_width, - LayerExtension &parents_out); -//---------------------------------------------------------------------------------------------------------------------- -// Implementation -template +// Hash chunks of a layer of new children, outputting the next layer's parents template -void CurveTrees::hash_layer(const C &curve, +static void hash_layer(const C &curve, const LastChunkData *last_parent_chunk_ptr, const std::vector &child_scalars, const std::size_t children_start_idx, @@ -415,7 +202,7 @@ void CurveTrees::hash_layer(const C &curve, child_layer_last_hash_updated, last_parent_chunk_ptr, offset) - : this->get_new_parent(curve, chunk); + : get_new_parent(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::hash_layer(const C &curve, }; //---------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------- +// CurveTrees public member functions +//---------------------------------------------------------------------------------------------------------------------- +template<> +CurveTrees::LeafTuple CurveTrees::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 CurveTrees::TreeExtension CurveTrees::get_tree_extension( + const LastChunks &existing_last_chunks, + const std::vector &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 flattened_leaves = this->flatten_leaves(new_leaf_tuples); + + // Hash the leaf layer + LayerExtension 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_last_chunk_ptr = (c1_last_chunks.size() <= c1_last_idx) + ? nullptr + : &c1_last_chunks[c1_last_idx]; + + const LastChunkData *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(m_c2, + c2_last_chunk_ptr, + c1_last_chunk_ptr, + c2_child_extension); + + LayerExtension c1_layer_extension; + hash_layer(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(m_c1, + c1_last_chunk_ptr, + c2_last_chunk_ptr, + c1_child_extension); + + LayerExtension c2_layer_extension; + hash_layer(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 +std::vector CurveTrees::flatten_leaves(const std::vector &leaves) const +{ + std::vector 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 diff --git a/src/fcmp/curve_trees.h b/src/fcmp/curve_trees.h index 82274d23c..903a6cc53 100644 --- a/src/fcmp/curve_trees.h +++ b/src/fcmp/curve_trees.h @@ -37,10 +37,45 @@ // forward declarations class CurveTreesUnitTest; + namespace fcmp { +namespace curve_trees +{ +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +// Hash a chunk of new children +template +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 +struct LayerExtension final +{ + std::size_t start_idx; + std::vector hashes; +}; -// TODO: longer descriptions +// Useful data from the last chunk in a layer +template +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 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 tuples; }; - // A layer of contiguous hashes starting from a specific start_idx in the tree - template - struct LayerExtension final - { - std::size_t start_idx; - std::vector 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> c2_layer_extensions; }; - // Useful data from the last chunk in a layer - template - 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 flatten_leaves(const std::vector &leaves) const; - // TODO: make below functions static functions inside curve_trees.cpp - // Hash a chunk of new children - template - 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::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 *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 - std::vector next_child_scalars_from_children(const C_CHILD &c_child, - const LastChunkData *last_child_chunk_ptr, - const LastChunkData *last_parent_chunk_ptr, - const LayerExtension &children); - - // Hash chunks of a layer of new children, outputting the next layer's parents - template - void hash_layer(const C &curve, - const LastChunkData *last_parent_chunk_ptr, - const std::vector &child_scalars, - const std::size_t children_start_idx, - const std::size_t chunk_width, - LayerExtension &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; +//---------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------- +} //namespace curve_trees } //namespace fcmp diff --git a/src/fcmp/tower_cycle.cpp b/src/fcmp/tower_cycle.cpp index c954f7aff..cca657fe4 100644 --- a/src/fcmp/tower_cycle.cpp +++ b/src/fcmp/tower_cycle.cpp @@ -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 +void extend_zeroes(const C &curve, + const std::size_t num_zeroes, + std::vector &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(const Helios &curve, + const std::size_t num_zeroes, + std::vector &zeroes_inout); + +template void extend_zeroes(const Selene &curve, + const std::size_t num_zeroes, + std::vector &zeroes_inout); +//---------------------------------------------------------------------------------------------------------------------- +template +void extend_scalars_from_cycle_points(const C_POINTS &curve, + const std::vector &points, + std::vector &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(const Helios &curve, + const std::vector &points, + std::vector &scalars_out); + +template void extend_scalars_from_cycle_points(const Selene &curve, + const std::vector &points, + std::vector &scalars_out); +//---------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------- } //namespace tower_cycle } //namespace fcmp diff --git a/src/fcmp/tower_cycle.h b/src/fcmp/tower_cycle.h index dcd3092cd..bf08bd04f 100644 --- a/src/fcmp/tower_cycle.h +++ b/src/fcmp/tower_cycle.h @@ -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 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 -static void extend_zeroes(const C &curve, +template +void extend_zeroes(const C &curve, const std::size_t num_zeroes, - std::vector &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 &zeroes_inout); //---------------------------------------------------------------------------------------------------------------------- -// TODO: move impl into cpp -template -static void extend_scalars_from_cycle_points(const C_POINTS &curve, +template +void extend_scalars_from_cycle_points(const C_POINTS &curve, const std::vector &points, - std::vector &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 &scalars_out); //---------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------- -}//namespace curves +}//namespace tower_cycle }//namespace fcmp diff --git a/tests/unit_tests/curve_trees.cpp b/tests/unit_tests/curve_trees.cpp index f0723690a..44f123b7a 100644 --- a/tests/unit_tests/curve_trees.cpp +++ b/tests/unit_tests/curve_trees.cpp @@ -35,7 +35,7 @@ // CurveTreesUnitTest helpers //---------------------------------------------------------------------------------------------------------------------- template -static CurveTreesV1::LastChunkData get_last_child_layer_chunk(const C &curve, +static fcmp::curve_trees::LastChunkData 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 get_last_child_layer_chunk(const C &curve, const std::size_t child_offset = child_layer_size % chunk_width; - return CurveTreesV1::LastChunkData{ + return fcmp::curve_trees::LastChunkData{ .child_offset = child_offset, .last_child = curve.clone(last_child), .last_parent = curve.clone(last_parent), @@ -56,6 +56,39 @@ static CurveTreesV1::LastChunkData get_last_child_layer_chunk(const C &curve, }; } //---------------------------------------------------------------------------------------------------------------------- +template +static bool validate_layer(const C_PARENT &c_parent, + const CurveTreesUnitTest::Layer &parents, + const std::vector &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 &c2_ext = c2_extensions[c2_idx]; + const fcmp::curve_trees::LayerExtension &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 &c1_ext = c1_extensions[c1_idx]; + const fcmp::curve_trees::LayerExtension &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 -bool CurveTreesUnitTest::validate_layer(const C_PARENT &c_parent, - const CurveTreesUnitTest::Layer &parents, - const std::vector &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(m_curve_trees.m_c2, + const bool valid = validate_layer(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( + const bool valid = validate_layer( 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(m_curve_trees.m_c2, + return validate_layer(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 &last_chunk = c2_last_chunks[c2_idx]; + const fcmp::curve_trees::LastChunkData &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 &last_chunk = c1_last_chunks[c1_idx]; + const fcmp::curve_trees::LastChunkData &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 &c2_layer = c2_extensions[c2_idx]; + const fcmp::curve_trees::LayerExtension &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 &c1_layer = c1_extensions[c1_idx]; + const fcmp::curve_trees::LayerExtension &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); diff --git a/tests/unit_tests/curve_trees.h b/tests/unit_tests/curve_trees.h index b17b5a05f..cd3d8f370 100644 --- a/tests/unit_tests/curve_trees.h +++ b/tests/unit_tests/curve_trees.h @@ -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; +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 - bool validate_layer(const C_PARENT &c_parent, - const Layer &parents, - const std::vector &child_scalars, - const std::size_t max_chunk_size); - private: CurveTreesV1 &m_curve_trees; };