-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #52 from cryptochangements34/master
Verify address checksum
- Loading branch information
Showing
5 changed files
with
1,488 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,322 @@ | ||
<?php /* -*- coding: utf-8; indent-tabs-mode: t; tab-width: 4 -*- | ||
vim: ts=4 noet ai */ | ||
|
||
/** | ||
Streamable SHA-3 for PHP 5.2+, with no lib/ext dependencies! | ||
Copyright © 2018 Desktopd Developers | ||
This program is free software: you can redistribute it and/or modify | ||
it under the terms of the GNU Lesser General Public License as published by | ||
the Free Software Foundation, either version 3 of the License, or | ||
(at your option) any later version. | ||
This program is distributed in the hope that it will be useful, | ||
but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
GNU Lesser General Public License for more details. | ||
You should have received a copy of the GNU Lesser General Public License | ||
along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
@license LGPL-3+ | ||
@file | ||
*/ | ||
|
||
|
||
/** | ||
SHA-3 (FIPS-202) for PHP strings (byte arrays) (PHP 5.2.1+) | ||
PHP 7.0 computes SHA-3 about 4 times faster than PHP 5.2 - 5.6 (on x86_64) | ||
Based on the reference implementations, which are under CC-0 | ||
Reference: http://keccak.noekeon.org/ | ||
This uses PHP's native byte strings. Supports 32-bit as well as 64-bit | ||
systems. Also for LE vs. BE systems. | ||
*/ | ||
class SHA3 { | ||
const SHA3_224 = 1; | ||
const SHA3_256 = 2; | ||
const SHA3_384 = 3; | ||
const SHA3_512 = 4; | ||
|
||
const SHAKE128 = 5; | ||
const SHAKE256 = 6; | ||
|
||
const KECCAK_256 = 7; | ||
|
||
|
||
public static function init ($type = null) { | ||
switch ($type) { | ||
case self::SHA3_224: return new self (1152, 448, 0x06, 28); | ||
case self::SHA3_256: return new self (1088, 512, 0x06, 32); | ||
case self::SHA3_384: return new self (832, 768, 0x06, 48); | ||
case self::SHA3_512: return new self (576, 1024, 0x06, 64); | ||
case self::SHAKE128: return new self (1344, 256, 0x1f); | ||
case self::SHAKE256: return new self (1088, 512, 0x1f); | ||
case self::KECCAK_256: return new self (1088, 512, 0x01, 32); | ||
} | ||
|
||
throw new Exception ('Invalid operation type'); | ||
} | ||
|
||
|
||
/** | ||
Feed input to SHA-3 "sponge" | ||
*/ | ||
public function absorb ($data) { | ||
if (self::PHASE_INPUT != $this->phase) { | ||
throw new Exception ('No more input accepted'); | ||
} | ||
|
||
$rateInBytes = $this->rateInBytes; | ||
$this->inputBuffer .= $data; | ||
while (strlen ($this->inputBuffer) >= $rateInBytes) { | ||
list ($input, $this->inputBuffer) = array ( | ||
substr ($this->inputBuffer, 0, $rateInBytes) | ||
, substr ($this->inputBuffer, $rateInBytes)); | ||
|
||
$blockSize = $rateInBytes; | ||
for ($i = 0; $i < $blockSize; $i++) { | ||
$this->state[$i] = $this->state[$i] ^ $input[$i]; | ||
} | ||
|
||
$this->state = self::keccakF1600Permute ($this->state); | ||
$this->blockSize = 0; | ||
} | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
Get hash output | ||
*/ | ||
public function squeeze ($length = null) { | ||
$outputLength = $this->outputLength; // fixed length output | ||
if ($length && 0 < $outputLength && $outputLength != $length) { | ||
throw new Exception ('Invalid length'); | ||
} | ||
|
||
if (self::PHASE_INPUT == $this->phase) { | ||
$this->finalizeInput (); | ||
} | ||
|
||
if (self::PHASE_OUTPUT != $this->phase) { | ||
throw new Exception ('No more output allowed'); | ||
} | ||
if (0 < $outputLength) { | ||
$this->phase = self::PHASE_DONE; | ||
return $this->getOutputBytes ($outputLength); | ||
} | ||
|
||
$blockLength = $this->rateInBytes; | ||
list ($output, $this->outputBuffer) = array ( | ||
substr ($this->outputBuffer, 0, $length) | ||
, substr ($this->outputBuffer, $length)); | ||
$neededLength = $length - strlen ($output); | ||
$diff = $neededLength % $blockLength; | ||
if ($diff) { | ||
$readLength = (($neededLength - $diff) / $blockLength + 1) | ||
* $blockLength; | ||
} else { | ||
$readLength = $neededLength; | ||
} | ||
|
||
$read = $this->getOutputBytes ($readLength); | ||
$this->outputBuffer .= substr ($read, $neededLength); | ||
return $output . substr ($read, 0, $neededLength); | ||
} | ||
|
||
|
||
// internally used | ||
const PHASE_INIT = 1; | ||
const PHASE_INPUT = 2; | ||
const PHASE_OUTPUT = 3; | ||
const PHASE_DONE = 4; | ||
|
||
private $phase = self::PHASE_INIT; | ||
private $state; // byte array (string) | ||
private $rateInBytes; // positive integer | ||
private $suffix; // 8-bit unsigned integer | ||
private $inputBuffer = ''; // byte array (string): max length = rateInBytes | ||
private $outputLength = 0; | ||
private $outputBuffer = ''; | ||
|
||
|
||
public function __construct ($rate, $capacity, $suffix, $length = 0) { | ||
if (1600 != ($rate + $capacity)) { | ||
throw new Error ('Invalid parameters'); | ||
} | ||
if (0 != ($rate % 8)) { | ||
throw new Error ('Invalid rate'); | ||
} | ||
|
||
$this->suffix = $suffix; | ||
$this->state = str_repeat ("\0", 200); | ||
$this->blockSize = 0; | ||
|
||
$this->rateInBytes = $rate / 8; | ||
$this->outputLength = $length; | ||
$this->phase = self::PHASE_INPUT; | ||
return; | ||
} | ||
|
||
protected function finalizeInput () { | ||
$this->phase = self::PHASE_OUTPUT; | ||
|
||
$input = $this->inputBuffer; | ||
$inputLength = strlen ($input); | ||
if (0 < $inputLength) { | ||
$blockSize = $inputLength; | ||
for ($i = 0; $i < $blockSize; $i++) { | ||
$this->state[$i] = $this->state[$i] ^ $input[$i]; | ||
} | ||
|
||
$this->blockSize = $blockSize; | ||
} | ||
|
||
// Padding | ||
$rateInBytes = $this->rateInBytes; | ||
$this->state[$this->blockSize] = $this->state[$this->blockSize] | ||
^ chr ($this->suffix); | ||
if (($this->suffix & 0x80) != 0 | ||
&& $this->blockSize == ($rateInBytes - 1)) { | ||
$this->state = self::keccakF1600Permute ($this->state); | ||
} | ||
$this->state[$rateInBytes - 1] = $this->state[$rateInBytes - 1] ^ "\x80"; | ||
$this->state = self::keccakF1600Permute ($this->state); | ||
} | ||
|
||
protected function getOutputBytes ($outputLength) { | ||
// Squeeze | ||
$output = ''; | ||
while (0 < $outputLength) { | ||
$blockSize = min ($outputLength, $this->rateInBytes); | ||
$output .= substr ($this->state, 0, $blockSize); | ||
$outputLength -= $blockSize; | ||
if (0 < $outputLength) { | ||
$this->state = self::keccakF1600Permute ($this->state); | ||
} | ||
} | ||
|
||
return $output; | ||
} | ||
|
||
/** | ||
1600-bit state version of Keccak's permutation | ||
*/ | ||
protected static function keccakF1600Permute ($state) { | ||
$lanes = str_split ($state, 8); | ||
$R = 1; | ||
$values = "\1\2\4\10\20\40\100\200"; | ||
|
||
for ($round = 0; $round < 24; $round++) { | ||
// θ step | ||
$C = array (); | ||
for ($x = 0; $x < 5; $x++) { | ||
// (x, 0) (x, 1) (x, 2) (x, 3) (x, 4) | ||
$C[$x] = $lanes[$x] ^ $lanes[$x + 5] ^ $lanes[$x + 10] | ||
^ $lanes[$x + 15] ^ $lanes[$x + 20]; | ||
} | ||
for ($x = 0; $x < 5; $x++) { | ||
//$D = $C[($x + 4) % 5] ^ self::rotL64 ($C[($x + 1) % 5], 1); | ||
$D = $C[($x + 4) % 5] ^ self::rotL64One ($C[($x + 1) % 5]); | ||
for ($y = 0; $y < 5; $y++) { | ||
$idx = $x + 5 * $y; // x, y | ||
$lanes[$idx] = $lanes[$idx] ^ $D; | ||
} | ||
} | ||
unset ($C, $D); | ||
|
||
// ρ and π steps | ||
$x = 1; | ||
$y = 0; | ||
$current = $lanes[1]; // x, y | ||
for ($t = 0; $t < 24; $t++) { | ||
list ($x, $y) = array ($y, (2 * $x + 3 * $y) % 5); | ||
$idx = $x + 5 * $y; | ||
list ($current, $lanes[$idx]) = array ($lanes[$idx] | ||
, self::rotL64 ($current | ||
, (($t + 1) * ($t + 2) / 2) % 64)); | ||
} | ||
unset ($temp, $current); | ||
|
||
// χ step | ||
$temp = array (); | ||
for ($y = 0; $y < 5; $y++) { | ||
for ($x = 0; $x < 5; $x++) { | ||
$temp[$x] = $lanes[$x + 5 * $y]; | ||
} | ||
for ($x = 0; $x < 5; $x++) { | ||
$lanes[$x + 5 * $y] = $temp[$x] | ||
^ ((~ $temp[($x + 1) % 5]) & $temp[($x + 2) % 5]); | ||
|
||
} | ||
} | ||
unset ($temp); | ||
|
||
// ι step | ||
for ($j = 0; $j < 7; $j++) { | ||
$R = (($R << 1) ^ (($R >> 7) * 0x71)) & 0xff; | ||
if ($R & 2) { | ||
$offset = (1 << $j) - 1; | ||
$shift = $offset % 8; | ||
$octetShift = ($offset - $shift) / 8; | ||
$n = "\0\0\0\0\0\0\0\0"; | ||
$n[$octetShift] = $values[$shift]; | ||
|
||
$lanes[0] = $lanes[0] | ||
^ $n; | ||
//^ self::rotL64 ("\1\0\0\0\0\0\0\0", (1 << $j) - 1); | ||
} | ||
} | ||
} | ||
|
||
return implode ($lanes); | ||
} | ||
|
||
protected static function rotL64_64 ($n, $offset) { | ||
return ($n << $offset) & ($n >> (64 - $offset)); | ||
} | ||
|
||
/** | ||
64-bit bitwise left rotation (Little endian) | ||
*/ | ||
protected static function rotL64 ($n, $offset) { | ||
|
||
//$n = (binary) $n; | ||
//$offset = ((int) $offset) % 64; | ||
//if (8 != strlen ($n)) throw new Exception ('Invalid number'); | ||
//if ($offset < 0) throw new Exception ('Invalid offset'); | ||
|
||
$shift = $offset % 8; | ||
$octetShift = ($offset - $shift) / 8; | ||
$n = substr ($n, - $octetShift) . substr ($n, 0, - $octetShift); | ||
|
||
$overflow = 0x00; | ||
for ($i = 0; $i < 8; $i++) { | ||
$a = ord ($n[$i]) << $shift; | ||
$n[$i] = chr (0xff & $a | $overflow); | ||
$overflow = $a >> 8; | ||
} | ||
$n[0] = chr (ord ($n[0]) | $overflow); | ||
return $n; | ||
} | ||
|
||
/** | ||
64-bit bitwise left rotation (Little endian) | ||
*/ | ||
protected static function rotL64One ($n) { | ||
list ($n[0], $n[1], $n[2], $n[3], $n[4], $n[5], $n[6], $n[7]) | ||
= array ( | ||
chr (((ord ($n[0]) << 1) & 0xff) ^ (ord ($n[7]) >> 7)) | ||
,chr (((ord ($n[1]) << 1) & 0xff) ^ (ord ($n[0]) >> 7)) | ||
,chr (((ord ($n[2]) << 1) & 0xff) ^ (ord ($n[1]) >> 7)) | ||
,chr (((ord ($n[3]) << 1) & 0xff) ^ (ord ($n[2]) >> 7)) | ||
,chr (((ord ($n[4]) << 1) & 0xff) ^ (ord ($n[3]) >> 7)) | ||
,chr (((ord ($n[5]) << 1) & 0xff) ^ (ord ($n[4]) >> 7)) | ||
,chr (((ord ($n[6]) << 1) & 0xff) ^ (ord ($n[5]) >> 7)) | ||
,chr (((ord ($n[7]) << 1) & 0xff) ^ (ord ($n[6]) >> 7))); | ||
return $n; | ||
} | ||
} |
Oops, something went wrong.