Add comments and minor refactoring of canonization methods for clarity
Also guard against out-of-bounds access for untrusted input
This commit is contained in:
parent
fe8710a7aa
commit
ad3efeb28a
1 changed files with 46 additions and 12 deletions
58
vendor/equihash/src/pow.cpp
vendored
58
vendor/equihash/src/pow.cpp
vendored
|
|
@ -199,39 +199,73 @@ Proof Equihash::FindProof( Nonce _nonce )
|
||||||
|
|
||||||
Proof Proof::CanonizeIndexes()const
|
Proof Proof::CanonizeIndexes()const
|
||||||
{
|
{
|
||||||
|
// We consider the index values in the inputs array to be the leaf nodes of a binary
|
||||||
|
// tree, and the inner nodes to be labelled with the XOR of the corresponding vector
|
||||||
|
// elements.
|
||||||
|
//
|
||||||
|
// Define a binary tree to be canonically sorted if, for each inner node, the least
|
||||||
|
// leaf descendant of the left child is less than the least leaf descendant of the
|
||||||
|
// right child.
|
||||||
|
//
|
||||||
|
// This method puts the inputs into canonical order without altering the inner node
|
||||||
|
// labels. Thus canonization preserves the validity of the proof and the
|
||||||
|
// footprint of Wagner's algorithm.
|
||||||
|
//
|
||||||
|
// We use a bottom-up traversal, dividing the input into successively larger power-of-2
|
||||||
|
// blocks and swapping the two half-blocks if non-canonical.
|
||||||
|
//
|
||||||
|
// Say a block is least-first if the least element is the first element.
|
||||||
|
//
|
||||||
|
// If each half-block is least-first, the conditional swap ensures the full block will also
|
||||||
|
// be least-first. The half-blocks in the initial iteration are obviously least-first
|
||||||
|
// (they only have a single element!). So by induction, at each later iteration the half-blocks
|
||||||
|
// of that iteration are least-first (since they were the full blocks of the previous iteration,
|
||||||
|
// which were made least-first by the previous iteration's conditional swap).
|
||||||
|
//
|
||||||
|
// As a consequence, no search is necessary to find the least element in each half-block,
|
||||||
|
// it is always the first element in the half-block.
|
||||||
|
|
||||||
std::vector< uint32_t > new_inputs = inputs;
|
std::vector< uint32_t > new_inputs = inputs;
|
||||||
|
|
||||||
size_t step = 1;
|
size_t input_size = inputs.size();
|
||||||
while( step < new_inputs.size() )
|
size_t half_size = 1;
|
||||||
|
size_t block_size = 2;
|
||||||
|
while( block_size <= input_size )
|
||||||
{
|
{
|
||||||
for( size_t i=0; i<new_inputs.size(); i+=step+step )
|
for( size_t i=0; i+block_size<=input_size; i+=block_size )
|
||||||
{
|
{
|
||||||
auto ita = new_inputs.begin()+i, itb = ita+step;
|
auto ita = new_inputs.begin()+i, itb = ita+half_size;
|
||||||
if( (*ita) >= (*itb) )
|
if( (*ita) >= (*itb) )
|
||||||
{
|
{
|
||||||
std::swap_ranges( ita, itb, itb );
|
std::swap_ranges( ita, itb, itb );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
step += step;
|
half_size = block_size;
|
||||||
|
block_size += block_size;
|
||||||
}
|
}
|
||||||
return Proof(n, k, seed, nonce, new_inputs);
|
return Proof(n, k, seed, nonce, new_inputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Proof::CheckIndexesCanon()const
|
bool Proof::CheckIndexesCanon()const
|
||||||
{
|
{
|
||||||
bool was_ok = true;
|
// This method is logically identical to CanonizeIndexes() but will return false
|
||||||
size_t step = 1;
|
// instead of swapping elements.
|
||||||
while( step < inputs.size() )
|
|
||||||
|
size_t input_size = inputs.size();
|
||||||
|
size_t half_size = 1;
|
||||||
|
size_t block_size = 2;
|
||||||
|
while( block_size <= input_size )
|
||||||
{
|
{
|
||||||
for( size_t i=0; i<inputs.size(); i+=step+step )
|
for( size_t i=0; i+block_size<=input_size; i+=block_size )
|
||||||
{
|
{
|
||||||
auto ita = inputs.begin()+i, itb = ita+step;
|
auto ita = inputs.begin()+i, itb = ita+half_size;
|
||||||
if( (*ita) >= (*itb) )
|
if( (*ita) >= (*itb) )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
step += step;
|
half_size = block_size;
|
||||||
|
block_size += block_size;
|
||||||
}
|
}
|
||||||
return was_ok;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Proof::Test()
|
bool Proof::Test()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue