<?php
namespace SM3;
use ArrayAccess;
use Exception;
use SM3\handler\ExtendedCompression;
use SM3\libs\WordConversion;
use SM3\types\BitString;
class SM3 implements ArrayAccess
{
const IV = '7380166f4914b2b9172442d7da8a0600a96f30bc163138aae38dee4db0fb0e4e';
private $message = '';
private $hash_value = '';
public function __construct($message)
{
if (is_int($message)) $message = (string)$message;
if (empty($message)) $message = '';
if (!is_string($message)) throw new Exception('参数类型必须为string,请检查后重新输入', 90001);
$this->message = $message;
$this->hash_value = $this->sm3();
}
private function sm3()
{
$m = new BitString($this->message);
$l = strlen($m);
$k = $l % 512;
$k = $k + 64 >= 512
? 512 - ($k % 448) - 1
: 512 - 64 - $k - 1;
$bin_l = new BitString($l);
$m_fill = new types\BitString(
$m # 原始消息m
. '1' # 拼个1
. str_pad('', $k, '0') # 拼上k个比特的0
. (
strlen($bin_l) >= 64
? substr($bin_l, 0, 64)
: str_pad($bin_l, 64, '0', STR_PAD_LEFT)
) # 64比特,l的二进制表示
);
$B = str_split($m_fill, 512);
$n = ($l + $k + 65) / 512;
if (count($B) !== $n) return false;
$V = array(
WordConversion::hex2bin(self::IV),
);
$extended = new ExtendedCompression();
foreach ($B as $key => $Bi) {
$V[$key + 1] = $extended->CF($V[$key], $Bi)->getBitString();
}
krsort($V);
reset($V);
$binary = current($V);
$hex = WordConversion::bin2hex($binary);
return $hex;
}
public function __toString()
{
return $this->hash_value;
}
/**
* Whether a offset exists
*
* @link https://php.net/manual/en/arrayaccess.offsetexists.php
*
* @param mixed $offset <p>
* An offset to check for.
* </p>
*
* @return bool true on success or false on failure.
* </p>
* <p>
* The return value will be casted to boolean if non-boolean was returned.
* @since 5.0.0
*/
public function offsetExists($offset)
{
return isset($this->hash_value[$offset]);
}
/**
* Offset to retrieve
*
* @link https://php.net/manual/en/arrayaccess.offsetget.php
*
* @param mixed $offset <p>
* The offset to retrieve.
* </p>
*
* @return mixed Can return all value types.
* @since 5.0.0
*/
public function offsetGet($offset)
{
return $this->hash_value[$offset];
}
/**
* Offset to set
*
* @link https://php.net/manual/en/arrayaccess.offsetset.php
*
* @param mixed $offset <p>
* The offset to assign the value to.
* </p>
* @param mixed $value <p>
* The value to set.
* </p>
*
* @return \SM3\SM3
* @since 5.0.0
*/
public function offsetSet($offset, $value)
{
$this->hash_value[$offset] = $value;
return $this;
}
/**
* Offset to unset
*
* @link https://php.net/manual/en/arrayaccess.offsetunset.php
*
* @param mixed $offset <p>
* The offset to unset.
* </p>
*
* @return void
* @since 5.0.0
*/
public function offsetUnset($offset)
{
unset($this->hash_value[$offset]);
}
}