/** * @param \ParagonIE\AsgardClient\Structures\MerkleTree $tree * @param string $prevhash * @param string $nexthash */ public function __construct(MerkleTree $tree, $prevhash = null, $nexthash = null) { $this->merkleTree = $tree; $this->currentHash = $tree->getRoot(); $this->previousHash = $prevhash; $this->nextHash = $nexthash; if (empty($prevhash)) { $this->tailHash = $this->currentHash; } else { $this->tailHash = \Sodium::crypto_generichash(\bin2hex($this->previousHash) . \bin2hex($this->currentHash)); } }
/** * Verify the checksums on $tmp_file for the package we are verifying * * @param array $blockdata * @param string $tmp_file * @return boolean */ private function verifyChecksums($blockdata, $tmp_file) { $matches = 0; $filedata = \file_get_contents($tmp_file); // Now let's check all of the hashes foreach ($blockdata['checksums'] as $algo => $hash) { switch ($algo) { case 'BLAKE2b': // We used libsodium $line = \Sodium::crypto_generichash($filedata); break; default: // A simple hash (SHA256, etc) $line = \hash($algo, $filedata, true); } if (\hash_equals($line, \Sodium::sodium_hex2bin($hash))) { ++$matches; } else { die("{$algo} hash did not match!"); } } unset($filedata); // explicitly free return $matches > 0; }
/** * Calculate the hash tree for a given dataset: * 0 => Merkle Root * 1 => Left Child * 2 => Right Child, * 3 => LL, 4 => LR * 5 => RL, 6 => RR, * ... * * @return array */ public function getTree() { $numLeaves = count($this->leaves); // get the next 2^N larger than our dataset $baseIterate = (int) pow(2, ceil(log($numLeaves, 2))); $hashes = []; // Initial population for ($i = 0; $i < $baseIterate; ++$i) { if ($i >= $numLeaves) { // Following Bitcoin's lead; keep hashing the remainder $hashes[] = $this->leaves[$numLeaves - 1]['hash']; } else { $hashes[] = $this->leaves[$i]['hash']; } } $tree = $hashes; // Let's hash together until we have one node left do { $tmp = []; // Iterate through the first level of the tree $j = 0; for ($i = 0; $i < $baseIterate; $i += 2) { $tmp[$j] = \Sodium::crypto_generichash($hashes[$i] . $hashes[$i + 1]); \array_unshift($tree, $tmp[$j]); ++$j; } $hashes = $tmp; $baseIterate = $baseIterate >> 1; } while ($baseIterate > 1); return $tree; }