]> granicus.if.org Git - php/commitdiff
Implement SHA3 hashing algorithm
authorSara Golemon <pollita@php.net>
Fri, 16 Oct 2015 02:13:04 +0000 (19:13 -0700)
committerSara Golemon <sgolemon@fb.com>
Fri, 16 Oct 2015 03:36:49 +0000 (20:36 -0700)
ext/hash/config.m4
ext/hash/hash.c
ext/hash/hash_sha3.c [new file with mode: 0644]
ext/hash/php_hash.h
ext/hash/php_hash_sha3.h [new file with mode: 0644]
ext/hash/tests/hash_algos.phpt
ext/hash/tests/hash_copy_001.phpt
ext/hash/tests/sha3.phpt [new file with mode: 0644]

index 5174db3b71fa912a9d6ecf543a567d35b0304af0..703cf14a3022a61d57d1dd724028b0c239615b56 100644 (file)
@@ -27,11 +27,11 @@ if test "$PHP_HASH" != "no"; then
   
   EXT_HASH_SOURCES="hash.c hash_md.c hash_sha.c hash_ripemd.c hash_haval.c \
     hash_tiger.c hash_gost.c hash_snefru.c hash_whirlpool.c hash_adler32.c \
-    hash_crc32.c hash_fnv.c hash_joaat.c"
+    hash_crc32.c hash_fnv.c hash_joaat.c hash_sha3.c"
   EXT_HASH_HEADERS="php_hash.h php_hash_md.h php_hash_sha.h php_hash_ripemd.h \
     php_hash_haval.h php_hash_tiger.h php_hash_gost.h php_hash_snefru.h \
     php_hash_whirlpool.h php_hash_adler32.h php_hash_crc32.h \
-    php_hash_fnv.h php_hash_joaat.h"
+    php_hash_fnv.h php_hash_joaat.h php_hash_sha3.h"
   
   PHP_NEW_EXTENSION(hash, $EXT_HASH_SOURCES, $ext_shared)
   ifdef([PHP_INSTALL_HEADERS], [
index c1a94c2d0943b5af10103b1fd65396c5f40561a7..cc94fb220dc4bb68c38bd9246e11557ee8ae17d4 100644 (file)
@@ -1014,6 +1014,10 @@ PHP_MINIT_FUNCTION(hash)
        php_hash_register_algo("sha256",                &php_hash_sha256_ops);
        php_hash_register_algo("sha384",                &php_hash_sha384_ops);
        php_hash_register_algo("sha512",                &php_hash_sha512_ops);
+       php_hash_register_algo("sha3-224",              &php_hash_sha3_224_ops);
+       php_hash_register_algo("sha3-256",              &php_hash_sha3_256_ops);
+       php_hash_register_algo("sha3-384",              &php_hash_sha3_384_ops);
+       php_hash_register_algo("sha3-512",              &php_hash_sha3_512_ops);
        php_hash_register_algo("ripemd128",             &php_hash_ripemd128_ops);
        php_hash_register_algo("ripemd160",             &php_hash_ripemd160_ops);
        php_hash_register_algo("ripemd256",             &php_hash_ripemd256_ops);
diff --git a/ext/hash/hash_sha3.c b/ext/hash/hash_sha3.c
new file mode 100644 (file)
index 0000000..2fb24b3
--- /dev/null
@@ -0,0 +1,215 @@
+#include "php_hash_sha3.h"
+
+#if (defined(__APPLE__) || defined(__APPLE_CC__)) && \
+    (defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__))
+# if defined(__LITTLE_ENDIAN__)
+#  undef WORDS_BIGENDIAN
+# else
+#  if defined(__BIG_ENDIAN__)
+#   define WORDS_BIGENDIAN
+#  endif
+# endif
+#endif
+
+inline php_hash_uint64 rol64(php_hash_uint64 v, unsigned char b) {
+       return (v << b) | (v >> (64 - b));
+}
+inline unsigned char idx(unsigned char x, unsigned char y) {
+       return x + (5 * y);
+}
+
+#ifdef WORDS_BIGENDIAN
+inline php_hash_uint64 load64(const unsigned char* x) {
+       php_hash_uint64 ret = 0;
+       for (unsigned char i = 7; i >= 0; --i) {
+               ret <<= 8;
+               ret |= x[i];
+       }
+       return ret;
+}
+inline void store64(const unsigned char* x, php_hash_uint64 val) {
+       for (unsigned char i = 0; i < 8; ++i) {
+               x[i] = val & 0xFF;
+               val >>= 8;
+       }
+}
+inline void xor64(const unsigned char* x, php_hash_uint64 val) {
+       for (unsigned char i = 0; i < 8; ++i) {
+               x[i] ^= val & 0xFF;
+               val >>= 8;
+       }
+}
+# define readLane(x, y)     load64(ctx->state+sizeof(php_hash_uint64)*idx(x, y))
+# define writeLane(x, y, v) store64(ctx->state+sizeof(php_hash_uint64)*idx(x, y), v)
+# define XORLane(x, y, v)   xor64(ctx->state+sizeof(php_hash_uint64)*idx(x, y), v)
+#else
+# define readLane(x, y)     (((php_hash_uint64*)ctx->state)[idx(x,y)])
+# define writeLane(x, y, v) (((php_hash_uint64*)ctx->state)[idx(x,y)] = v)
+# define XORLane(x, y, v)   (((php_hash_uint64*)ctx->state)[idx(x,y)] ^= v)
+#endif
+
+inline char LFSR86540(unsigned char* pLFSR)
+{
+       unsigned char LFSR = *pLFSR;
+       char result = LFSR & 0x01;
+       if (LFSR & 0x80) {
+               // Primitive polynomial over GF(2): x^8+x^6+x^5+x^4+1
+               LFSR = (LFSR << 1) ^ 0x71;
+       } else {
+               LFSR <<= 1;
+       }
+       *pLFSR = LFSR;
+       return result;
+}
+
+static void permute(PHP_SHA3_CTX* ctx) {
+       unsigned char LFSRstate = 0x01;
+       unsigned char round;
+
+       for (round = 0; round < 24; ++round) {
+               { // Theta step (see [Keccak Reference, Section 2.3.2])
+                       php_hash_uint64 C[5], D;
+                       unsigned char x, y;
+                       for (x = 0; x < 5; ++x) {
+                               C[x] = readLane(x, 0) ^ readLane(x, 1) ^
+                               readLane(x, 2) ^ readLane(x, 3) ^ readLane(x, 4);
+                       }
+                       for (x = 0; x < 5; ++x) {
+                               D = C[(x+4)%5] ^ rol64(C[(x+1)%5], 1);
+                               for (y = 0; y < 5; ++y) {
+                                       XORLane(x, y, D);
+                               }
+                       }
+               }
+
+               { // p and Pi steps (see [Keccak Reference, Sections 2.3.3 and 2.3.4])
+                       unsigned char x = 1, y = 0, t;
+                       php_hash_uint64 current = readLane(x, y);
+                       for (t = 0; t < 24; ++t) {
+                               unsigned char r = ((t + 1) * (t + 2) / 2) % 64;
+                               unsigned char Y = (2*x + 3*y) % 5;
+                               x = y; y = Y;
+                               php_hash_uint64 temp = readLane(x, y);
+                               writeLane(x, y, rol64(current, r));
+                               current = temp;
+                       }
+               }
+
+               { // X step (see [Keccak Reference, Section 2.3.1])
+                       unsigned char x, y;
+                       for (y = 0; y < 5; ++y) {
+                               php_hash_uint64 temp[5];
+                               for (x = 0; x < 5; ++x) {
+                                       temp[x] = readLane(x, y);
+                               }
+                               for (x = 0; x < 5; ++x) {
+                                       writeLane(x, y, temp[x] ^((~temp[(x+1)%5]) & temp[(x+2)%5]));
+                               }
+                       }
+               }
+
+               { // i step (see [Keccak Reference, Section 2.3.5])
+               unsigned char j;
+                       for (j = 0; j < 7; ++j) {
+                               if (LFSR86540(&LFSRstate)) {
+                                       php_hash_uint64 bitPos = (1<<j) - 1;
+                                       XORLane(0, 0, (php_hash_uint64)1 << bitPos);
+                               }
+                       }
+               }
+       }
+}
+
+// ==========================================================================
+
+static void PHP_SHA3_Init(PHP_SHA3_CTX* ctx,
+                          int bits) {
+       memset(ctx, 0, sizeof(PHP_SHA3_CTX));
+}
+
+static void PHP_SHA3_Update(PHP_SHA3_CTX* ctx,
+                            const unsigned char* buf,
+                            unsigned int count,
+                            int block_size) {
+       while (count > 0) {
+               int len = block_size - ctx->pos;
+               if (len > count) len = count;
+               count -= len;
+               while (len-- > 0) {
+                       ctx->state[ctx->pos++] ^= *(buf++);
+               }
+               if (ctx->pos >= block_size) {
+                       permute(ctx);
+                       ctx->pos = 0;
+               }
+       }
+}
+
+static void PHP_SHA3_Final(unsigned char* digest,
+                           PHP_SHA3_CTX* ctx,
+                           int block_size,
+                           int digest_size) {
+       int len = digest_size;
+
+       // Pad state to finalize
+       ctx->state[ctx->pos++] ^= 0x06;
+       ctx->state[block_size-1] ^= 0x80;
+       permute(ctx);
+
+       // Square output for digest
+       for(;;) {
+               int bs = (len < block_size) ? len : block_size;
+               memcpy(digest, ctx->state, bs);
+               digest += bs;
+               len -= bs;
+               if (!len) break;
+               permute(ctx);
+       }
+
+       // Zero out context
+       memset(ctx, 0, sizeof(PHP_SHA3_CTX));
+}
+
+// ==========================================================================
+
+#define DECLARE_SHA3_OPS(bits) \
+void PHP_SHA3##bits##Init(PHP_SHA3_##bits##_CTX* ctx) { \
+       PHP_SHA3_Init(ctx, bits); \
+} \
+void PHP_SHA3##bits##Update(PHP_SHA3_##bits##_CTX* ctx, \
+                            const unsigned char* input, \
+                            unsigned int inputLen) { \
+       PHP_SHA3_Update(ctx, input, inputLen, \
+                    (1600 - (2 * bits)) >> 3); \
+} \
+void PHP_SHA3##bits##Final(unsigned char* digest, \
+                           PHP_SHA3_##bits##_CTX* ctx) { \
+       PHP_SHA3_Final(digest, ctx, \
+                   (1600 - (2 * bits)) >> 3, \
+                   bits >> 3); \
+} \
+const php_hash_ops php_hash_sha3_##bits##_ops = { \
+       (php_hash_init_func_t) PHP_SHA3##bits##Init, \
+       (php_hash_update_func_t) PHP_SHA3##bits##Update, \
+       (php_hash_final_func_t) PHP_SHA3##bits##Final, \
+       php_hash_copy, \
+       bits >> 3, \
+       (1600 - (2 * bits)) >> 3, \
+       sizeof(PHP_SHA3_##bits##_CTX) \
+}
+
+DECLARE_SHA3_OPS(224);
+DECLARE_SHA3_OPS(256);
+DECLARE_SHA3_OPS(384);
+DECLARE_SHA3_OPS(512);
+
+#undef DECLARE_SHA3_OPS
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
index c8104710baf4ad3b1be0f2bb163b4f5e8ab848b3..2156116696e4c236aa3f8cd1a28f382104cbc600 100644 (file)
@@ -68,6 +68,10 @@ extern const php_hash_ops php_hash_sha224_ops;
 extern const php_hash_ops php_hash_sha256_ops;
 extern const php_hash_ops php_hash_sha384_ops;
 extern const php_hash_ops php_hash_sha512_ops;
+extern const php_hash_ops php_hash_sha3_224_ops;
+extern const php_hash_ops php_hash_sha3_256_ops;
+extern const php_hash_ops php_hash_sha3_384_ops;
+extern const php_hash_ops php_hash_sha3_512_ops;
 extern const php_hash_ops php_hash_ripemd128_ops;
 extern const php_hash_ops php_hash_ripemd160_ops;
 extern const php_hash_ops php_hash_ripemd256_ops;
diff --git a/ext/hash/php_hash_sha3.h b/ext/hash/php_hash_sha3.h
new file mode 100644 (file)
index 0000000..65196ab
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 7                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2015 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.01 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_01.txt                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Author: Sara Golemon <pollita@php.net>                               |
+   +----------------------------------------------------------------------+
+*/
+
+#ifndef PHP_HASH_SHA3_H
+#define PHP_HASH_SHA3_H
+
+#include "php.h"
+#include "ext/hash/php_hash.h"
+
+typedef struct {
+       unsigned char state[200]; // 5 * 5 * sizeof(uint64)
+       php_hash_uint32 pos;
+} PHP_SHA3_CTX;
+
+typedef PHP_SHA3_CTX PHP_SHA3_224_CTX;
+typedef PHP_SHA3_CTX PHP_SHA3_256_CTX;
+typedef PHP_SHA3_CTX PHP_SHA3_384_CTX;
+typedef PHP_SHA3_CTX PHP_SHA3_512_CTX;
+
+PHP_HASH_API void PHP_SHA3224Init(PHP_SHA3_224_CTX*);
+PHP_HASH_API void PHP_SHA3224Update(PHP_SHA3_224_CTX*, const unsigned char*, unsigned int);
+PHP_HASH_API void PHP_SAH3224Final(unsigned char[32], PHP_SHA3_224_CTX*);
+
+PHP_HASH_API void PHP_SHA3256Init(PHP_SHA3_256_CTX*);
+PHP_HASH_API void PHP_SHA3256Update(PHP_SHA3_256_CTX*, const unsigned char*, unsigned int);
+PHP_HASH_API void PHP_SAH3256Final(unsigned char[32], PHP_SHA3_256_CTX*);
+
+PHP_HASH_API void PHP_SHA3384Init(PHP_SHA3_384_CTX*);
+PHP_HASH_API void PHP_SHA3384Update(PHP_SHA3_384_CTX*, const unsigned char*, unsigned int);
+PHP_HASH_API void PHP_SAH3384Final(unsigned char[32], PHP_SHA3_384_CTX*);
+
+PHP_HASH_API void PHP_SHA3512Init(PHP_SHA3_512_CTX*);
+PHP_HASH_API void PHP_SHA3512Update(PHP_SHA3_512_CTX*, const unsigned char*, unsigned int);
+PHP_HASH_API void PHP_SAH3512Final(unsigned char[32], PHP_SHA3_512_CTX*);
+
+#endif
index f2d6fc3ffb3022a9f1e41d829c6af789f7e9b216..ca1dcad4566a37f907429485d887c447438e5c21 100644 (file)
@@ -18,7 +18,7 @@ var_dump(hash_algos());
 ===Done===
 --EXPECTF--
 *** Testing hash_algos() : basic functionality ***
-array(46) {
+array(50) {
   [%d]=>
   string(3) "md2"
   [%d]=>
@@ -36,6 +36,14 @@ array(46) {
   [%d]=>
   string(6) "sha512"
   [%d]=>
+  string(8) "sha3-224"
+  [%d]=>
+  string(8) "sha3-256"
+  [%d]=>
+  string(8) "sha3-384"
+  [%d]=>
+  string(8) "sha3-512"
+  [%d]=>
   string(9) "ripemd128"
   [%d]=>
   string(9) "ripemd160"
index f9fe7cc552efe0de9906b493507a421dbe3c64fe..67d16aaf88de908ba352722d7be330c31b9a3dd6 100644 (file)
@@ -55,6 +55,18 @@ string(96) "6950d861ace4102b803ab8b3779d2f471968233010d2608974ab89804cef6f76162b
 string(6) "sha512"
 string(128) "caced3db8e9e3a5543d5b933bcbe9e7834e6667545c3f5d4087b58ec8d78b4c8a4a5500c9b88f65f7368810ba9905e51f1cff3b25a5dccf76634108fb4e7ce13"
 string(128) "caced3db8e9e3a5543d5b933bcbe9e7834e6667545c3f5d4087b58ec8d78b4c8a4a5500c9b88f65f7368810ba9905e51f1cff3b25a5dccf76634108fb4e7ce13"
+string(8) "sha3-224"
+string(56) "7e1126cffee98e5c4b0e9dd5c6efabd5c9356d668e9a2d3cfab724d4"
+string(56) "7e1126cffee98e5c4b0e9dd5c6efabd5c9356d668e9a2d3cfab724d4"
+string(8) "sha3-256"
+string(64) "834abfed9197af09cbe66b7748c65a050a3755ef7a556d6764eb6eabc93b4c7a"
+string(64) "834abfed9197af09cbe66b7748c65a050a3755ef7a556d6764eb6eabc93b4c7a"
+string(8) "sha3-384"
+string(96) "c9016992586f7a8663c5379ed892349c1140ad258f7c44ee82f61f0b8cb75c675012ea94dc1314e06699be2d1465f67b"
+string(96) "c9016992586f7a8663c5379ed892349c1140ad258f7c44ee82f61f0b8cb75c675012ea94dc1314e06699be2d1465f67b"
+string(8) "sha3-512"
+string(128) "5f85341bc9c6621406bf1841c4ce01727ea8759fdf2927106c3e70a75ad9fffd095b87f995aeee844e1a2c287e1195ce809b9bdb1c31258f7fc098175b6de0b4"
+string(128) "5f85341bc9c6621406bf1841c4ce01727ea8759fdf2927106c3e70a75ad9fffd095b87f995aeee844e1a2c287e1195ce809b9bdb1c31258f7fc098175b6de0b4"
 string(9) "ripemd128"
 string(32) "5f1bc5f5aeaf747574dd34a6535cd94a"
 string(32) "5f1bc5f5aeaf747574dd34a6535cd94a"
@@ -193,6 +205,18 @@ string(96) "0d44981d04bb11b1ef75d5c2932bd0aa2785e7bc454daac954d77e2ca10047879b58
 string(6) "sha512"
 string(128) "caced3db8e9e3a5543d5b933bcbe9e7834e6667545c3f5d4087b58ec8d78b4c8a4a5500c9b88f65f7368810ba9905e51f1cff3b25a5dccf76634108fb4e7ce13"
 string(128) "28d7c721433782a880f840af0c3f3ea2cad4ef55de2114dda9d504cedeb110e1cf2519c49e4b5da3da4484bb6ba4fd1621ceadc6408f4410b2ebe9d83a4202c2"
+string(8) "sha3-224"
+string(56) "7e1126cffee98e5c4b0e9dd5c6efabd5c9356d668e9a2d3cfab724d4"
+string(56) "9a21a5464794c2c9784df50cf89cf72234e11941bddaee93f912753e"
+string(8) "sha3-256"
+string(64) "834abfed9197af09cbe66b7748c65a050a3755ef7a556d6764eb6eabc93b4c7a"
+string(64) "57aa7a90f29b5ab66592760592780da247fd39b4c911773687450f9df8cc8ed0"
+string(8) "sha3-384"
+string(96) "c9016992586f7a8663c5379ed892349c1140ad258f7c44ee82f61f0b8cb75c675012ea94dc1314e06699be2d1465f67b"
+string(96) "5d6d7e42b241288bc707b74c50f90a37d69a4afa854ca72021a22cb379356e53b6233aea1be2f33d393d6effa9b5e36c"
+string(8) "sha3-512"
+string(128) "5f85341bc9c6621406bf1841c4ce01727ea8759fdf2927106c3e70a75ad9fffd095b87f995aeee844e1a2c287e1195ce809b9bdb1c31258f7fc098175b6de0b4"
+string(128) "9b88c689bc13a36e6983b32e8ee9464d63b619f246ca451d1fe2a6c9670f01e71d0c8eb245f3204d27d27c056f2a0fef76a1e3bc30fb74cccbc984dbd4883ae6"
 string(9) "ripemd128"
 string(32) "5f1bc5f5aeaf747574dd34a6535cd94a"
 string(32) "f95f5e22b8875ee0c48219ae97f0674b"
diff --git a/ext/hash/tests/sha3.phpt b/ext/hash/tests/sha3.phpt
new file mode 100644 (file)
index 0000000..67fb22f
--- /dev/null
@@ -0,0 +1,56 @@
+--TEST--
+sha3 algorithm
+--SKIPIF--
+<?php if(!extension_loaded("hash")) print "skip"; ?>
+--FILE--
+<?php
+
+// Test vectors taken from a combination of NIST FIPS-202,
+// Wikipedia reference vectors,
+// and output from reference implementation
+$subjects = [
+  '',
+  'a',
+  'The quick brown fox jumps over the lazy dog',
+  'The quick brown fox jumps over the lazy dog.',
+  str_repeat('a', 257),
+  str_repeat("\xA3", 200),
+];
+foreach ($subjects as $subject) {
+  echo '== ', urlencode($subject), " ==\n";
+  foreach ([224, 256, 384, 512] as $bits) {
+    echo $bits, ': ', hash("sha3-$bits", $subject), "\n";
+  }
+}
+--EXPECT--
+==  ==
+224: 6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7
+256: a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a
+384: 0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004
+512: a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26
+== a ==
+224: 9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b
+256: 80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b
+384: 1815f774f320491b48569efec794d249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9
+512: 697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa803f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a
+== The+quick+brown+fox+jumps+over+the+lazy+dog ==
+224: d15dadceaa4d5d7bb3b48f446421d542e08ad8887305e28d58335795
+256: 69070dda01975c8c120c3aada1b282394e7f032fa9cf32f4cb2259a0897dfc04
+384: 7063465e08a93bce31cd89d2e3ca8f602498696e253592ed26f07bf7e703cf328581e1471a7ba7ab119b1a9ebdf8be41
+512: 01dedd5de4ef14642445ba5f5b97c15e47b9ad931326e4b0727cd94cefc44fff23f07bf543139939b49128caf436dc1bdee54fcb24023a08d9403f9b4bf0d450
+== The+quick+brown+fox+jumps+over+the+lazy+dog. ==
+224: 2d0708903833afabdd232a20201176e8b58c5be8a6fe74265ac54db0
+256: a80f839cd4f83f6c3dafc87feae470045e4eb0d366397d5c6ce34ba1739f734d
+384: 1a34d81695b622df178bc74df7124fe12fac0f64ba5250b78b99c1273d4b080168e10652894ecad5f1f4d5b965437fb9
+512: 18f4f4bd419603f95538837003d9d254c26c23765565162247483f65c50303597bc9ce4d289f21d1c2f1f458828e33dc442100331b35e7eb031b5d38ba6460f8
+== aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ==
+224: 10dd422d71c42ee102a0c4bd398b5b85470341a0794702c954b022ba
+256: 6d115e8744deef792419e8bdb8567d74844e0fa5c2d5e474a19de87ac001449f
+384: c9df41fa389101cde63447257835464d89fd3974e5813f3f58d30e0296e89486e2d4bfc2b4089cd3bb860a20263322b8
+512: 5008048b64c14975181175f157be4a780c3d443d2177edf323d57884bc7e3979b9b53bca1325e880df3da0d97c435693441cb5527fbe950f5585678dfbb37785
+== %A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3%A3 ==
+224: 9376816aba503f72f96ce7eb65ac095deee3be4bf9bbc2a1cb7e11e0
+256: 79f38adec5c20307a98ef76e8324afbfd46cfd81b22e3973c65fa1bd9de31787
+384: 1881de2ca7e41ef95dc4732b8f5f002b189cc1e42b74168ed1732649ce1dbcdd76197a31fd55ee989f2d7050dd473e8f
+512: e76dfad22084a8b1467fcf2ffa58361bec7628edf5f3fdc0e4805dc48caeeca81b7c13c30adf52a3659584739a2df46be589c51ca1a4a8416df6545a1ce8ba00
+