From d3e35be3caa2ec41efb2518c0217b1cdd849ff18 Mon Sep 17 00:00:00 2001 From: sneurlax Date: Fri, 24 Jun 2016 04:46:48 -0500 Subject: [PATCH] Added reference to BLAKE 256 Getting ready for Decred / DCR (&/ other BLAKE algo. coins?) --- README.md | 1 + .../engine/crypto/hash/FunBLAKE_256.hx | 669 ++++++++++++++++++ 2 files changed, 670 insertions(+) create mode 100644 com/fundoware/engine/crypto/hash/FunBLAKE_256.hx diff --git a/README.md b/README.md index fd82253..31f2047 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ * SHA-1, SHA-256, RIPEMD160 * Elliptic curve arithmetic * secp256k1 & NIST curves + * BLAKE 256 (work in progress) ### Other * Modular arithmetic (Fp) diff --git a/com/fundoware/engine/crypto/hash/FunBLAKE_256.hx b/com/fundoware/engine/crypto/hash/FunBLAKE_256.hx new file mode 100644 index 0000000..8cc9330 --- /dev/null +++ b/com/fundoware/engine/crypto/hash/FunBLAKE_256.hx @@ -0,0 +1,669 @@ +/*=========================================================================== + +hxBitcoin - pure HaXe cryptocurrency & cryptography library +http://hxbitcoin.com + +Copyright (c) 2016 Charles H. Batson III + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +===========================================================================*/ + +package com.fundoware.engine.crypto.hash; + +import com.fundoware.engine.bigint.FunMultiwordArithmetic; +import com.fundoware.engine.crypto.FunCryptoUtils; +import com.fundoware.engine.crypto.hash.impl.FunBlockHashBase; +import com.fundoware.engine.exception.FunExceptions; +import com.fundoware.engine.math.FunInteger; +import haxe.ds.Vector; +import haxe.io.Bytes; + +// See http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf +class FunBLAKE_256 extends FunBlockHashBase implements FunIHash +{ + //----------------------------------------------------------------------- + // Helpers + //----------------------------------------------------------------------- + + public static inline function HashString(s : String) : String + { + return FunHashTools.HashString(new FunBLAKE_256(), s); + } + + public static inline function HashBytes(data : Bytes) : String + { + return FunHashTools.HashBytes(new FunBLAKE_256(), data); + } + + //----------------------------------------------------------------------- + // Public interface + //----------------------------------------------------------------------- + + public static inline var kDigestSize : Int = 32; + public static inline var kBlockSize : Int = 64; + + public function new() + { + super(kBlockSize); + reset(); + } + + public override function reset() : Void + { + super.reset(); + h0 = 0x6a09e667; + h1 = 0xbb67ae85; + h2 = 0x3c6ef372; + h3 = 0xa54ff53a; + h4 = 0x510e527f; + h5 = 0x9b05688c; + h6 = 0x1f83d9ab; + h7 = 0x5be0cd19; + } + + public function addByte(byte : Int) : Void + { + addByteBE(byte); + } + + public function addBytes(bytes : Bytes, offset : Int, length : Int) : Void + { + addBytesBE(bytes, offset, length); + } + + public function finish(digest : Bytes, offset : Int) : Void + { + if ((offset + kDigestSize) > digest.length) + { + throw FunExceptions.FUN_BUFFER_TOO_SMALL; + } + + var len = m_length; + addByteBE(0x80); + while ((m_length & 0x3f) != 56) + { + addByteBE(0x00); + } + m_block.set(14, len >>> 29); + m_block.set(15, len << 3); + processBlock(); + + FunBlockHashBase.putBE(digest, offset + 0, h0); + FunBlockHashBase.putBE(digest, offset + 4, h1); + FunBlockHashBase.putBE(digest, offset + 8, h2); + FunBlockHashBase.putBE(digest, offset + 12, h3); + FunBlockHashBase.putBE(digest, offset + 16, h4); + FunBlockHashBase.putBE(digest, offset + 20, h5); + FunBlockHashBase.putBE(digest, offset + 24, h6); + FunBlockHashBase.putBE(digest, offset + 28, h7); + } + + public function getDigestSize() : Int + { + return kDigestSize; + } + + public function clear() : Void + { + super.doClear(); + FunCryptoUtils.clearVectorInt(m_w); + reset(); + } + + //----------------------------------------------------------------------- + // Private implementation + //----------------------------------------------------------------------- + + private override function processBlock() : Void + { + Vector.blit(m_block, 0, m_w, 0, 16); + + var ch : Int, maj : Int, s0 : Int, s1 : Int, temp1 : Int, temp2 : Int; + + for (i in 16 ... 64) + { + s0 = m_w.get(i - 15); + s1 = m_w.get(i - 2); + s0 = FunInteger.rotateRight(s0, 7) ^ FunInteger.rotateRight(s0, 18) ^ (s0 >>> 3); + s1 = FunInteger.rotateRight(s1, 17) ^ FunInteger.rotateRight(s1, 19) ^ (s1 >>> 10); + m_w.set(i, m_w.get(i - 16) + s0 + m_w.get(i - 7) + s1); + } + + var a = h0; + var b = h1; + var c = h2; + var d = h3; + var e = h4; + var f = h5; + var g = h6; + var h = h7; + + for (i in 0 ... 64) + { + s1 = FunInteger.rotateRight(e, 6) ^ FunInteger.rotateRight(e, 11) ^ FunInteger.rotateRight(e, 25); + ch = (e & f) ^ (~e & g); + temp1 = h + s1 + ch + s_k.get(i) + m_w.get(i); + s0 = FunInteger.rotateRight(a, 2) ^ FunInteger.rotateRight(a, 13) ^ FunInteger.rotateRight(a, 22); + maj = (a & b) ^ (a & c) ^ (b & c); + temp2 = s0 + maj; + + h = g; + g = f; + f = e; + e = d + temp1; + d = c; + c = b; + b = a; + a = temp1 + temp2; + } + + h0 += a; + h1 += b; + h2 += c; + h3 += d; + h4 += e; + h5 += f; + h6 += g; + h7 += h; + } + + private var h0 : Int; + private var h1 : Int; + private var h2 : Int; + private var h3 : Int; + private var h4 : Int; + private var h5 : Int; + private var h6 : Int; + private var h7 : Int; + private var m_w = new Vector(64); + private static var s_k = Vector.fromArrayCopy([ + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + ]); +} + +/* + BLAKE reference C implementation + Copyright (c) 2012 Jean-Philippe Aumasson + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . + */ +#include "blake.h" + + +void blake256_compress( state256 *S, const uint8_t *block ) +{ + uint32_t v[16], m[16], i; +#define ROT(x,n) (((x)<<(32-n))|( (x)>>(n))) +#define G(a,b,c,d,e) \ + v[a] += (m[sigma[i][e]] ^ u256[sigma[i][e+1]]) + v[b]; \ + v[d] = ROT( v[d] ^ v[a],16); \ + v[c] += v[d]; \ + v[b] = ROT( v[b] ^ v[c],12); \ + v[a] += (m[sigma[i][e+1]] ^ u256[sigma[i][e]])+v[b]; \ + v[d] = ROT( v[d] ^ v[a], 8); \ + v[c] += v[d]; \ + v[b] = ROT( v[b] ^ v[c], 7); + + for( i = 0; i < 16; ++i ) m[i] = U8TO32_BIG( block + i * 4 ); + + for( i = 0; i < 8; ++i ) v[i] = S->h[i]; + + v[ 8] = S->s[0] ^ u256[0]; + v[ 9] = S->s[1] ^ u256[1]; + v[10] = S->s[2] ^ u256[2]; + v[11] = S->s[3] ^ u256[3]; + v[12] = u256[4]; + v[13] = u256[5]; + v[14] = u256[6]; + v[15] = u256[7]; + + /* don't xor t when the block is only padding */ + if ( !S->nullt ) + { + v[12] ^= S->t[0]; + v[13] ^= S->t[0]; + v[14] ^= S->t[1]; + v[15] ^= S->t[1]; + } + + for( i = 0; i < 14; ++i ) + { + /* column step */ + G( 0, 4, 8, 12, 0 ); + G( 1, 5, 9, 13, 2 ); + G( 2, 6, 10, 14, 4 ); + G( 3, 7, 11, 15, 6 ); + /* diagonal step */ + G( 0, 5, 10, 15, 8 ); + G( 1, 6, 11, 12, 10 ); + G( 2, 7, 8, 13, 12 ); + G( 3, 4, 9, 14, 14 ); + } + + for( i = 0; i < 16; ++i ) S->h[i % 8] ^= v[i]; + + for( i = 0; i < 8 ; ++i ) S->h[i] ^= S->s[i % 4]; +} + + +void blake256_init( state256 *S ) +{ + S->h[0] = 0x6a09e667; + S->h[1] = 0xbb67ae85; + S->h[2] = 0x3c6ef372; + S->h[3] = 0xa54ff53a; + S->h[4] = 0x510e527f; + S->h[5] = 0x9b05688c; + S->h[6] = 0x1f83d9ab; + S->h[7] = 0x5be0cd19; + S->t[0] = S->t[1] = S->buflen = S->nullt = 0; + S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0; +} + + +void blake256_update( state256 *S, const uint8_t *in, uint64_t inlen ) +{ + int left = S->buflen; + int fill = 64 - left; + + /* data left and data received fill a block */ + if( left && ( inlen >= fill ) ) + { + memcpy( ( void * ) ( S->buf + left ), ( void * ) in, fill ); + S->t[0] += 512; + + if ( S->t[0] == 0 ) S->t[1]++; + + blake256_compress( S, S->buf ); + in += fill; + inlen -= fill; + left = 0; + } + + /* compress blocks of data received */ + while( inlen >= 64 ) + { + S->t[0] += 512; + + if ( S->t[0] == 0 ) S->t[1]++; + + blake256_compress( S, in ); + in += 64; + inlen -= 64; + } + + /* store any data left */ + if( inlen > 0 ) + { + memcpy( ( void * ) ( S->buf + left ), \ + ( void * ) in, ( size_t ) inlen ); + S->buflen = left + ( int )inlen; + } + else S->buflen = 0; +} + + +void blake256_final( state256 *S, uint8_t *out ) +{ + uint8_t msglen[8], zo = 0x01, oo = 0x81; + uint32_t lo = S->t[0] + ( S->buflen << 3 ), hi = S->t[1]; + + /* support for hashing more than 2^32 bits */ + if ( lo < ( S->buflen << 3 ) ) hi++; + + U32TO8_BIG( msglen + 0, hi ); + U32TO8_BIG( msglen + 4, lo ); + + if ( S->buflen == 55 ) /* one padding byte */ + { + S->t[0] -= 8; + blake256_update( S, &oo, 1 ); + } + else + { + if ( S->buflen < 55 ) /* enough space to fill the block */ + { + if ( !S->buflen ) S->nullt = 1; + + S->t[0] -= 440 - ( S->buflen << 3 ); + blake256_update( S, padding, 55 - S->buflen ); + } + else /* need 2 compressions */ + { + S->t[0] -= 512 - ( S->buflen << 3 ); + blake256_update( S, padding, 64 - S->buflen ); + S->t[0] -= 440; + blake256_update( S, padding + 1, 55 ); + S->nullt = 1; + } + + blake256_update( S, &zo, 1 ); + S->t[0] -= 8; + } + + S->t[0] -= 64; + blake256_update( S, msglen, 8 ); + U32TO8_BIG( out + 0, S->h[0] ); + U32TO8_BIG( out + 4, S->h[1] ); + U32TO8_BIG( out + 8, S->h[2] ); + U32TO8_BIG( out + 12, S->h[3] ); + U32TO8_BIG( out + 16, S->h[4] ); + U32TO8_BIG( out + 20, S->h[5] ); + U32TO8_BIG( out + 24, S->h[6] ); + U32TO8_BIG( out + 28, S->h[7] ); +} + + +void blake256_hash( uint8_t *out, const uint8_t *in, uint64_t inlen ) +{ + state256 S; + blake256_init( &S ); + blake256_update( &S, in, inlen ); + blake256_final( &S, out ); +} + + +void blake256_test() +{ + int i, v; + uint8_t in[72], out[32]; + uint8_t test1[] = + { + 0x0c, 0xe8, 0xd4, 0xef, 0x4d, 0xd7, 0xcd, 0x8d, + 0x62, 0xdf, 0xde, 0xd9, 0xd4, 0xed, 0xb0, 0xa7, + 0x74, 0xae, 0x6a, 0x41, 0x92, 0x9a, 0x74, 0xda, + 0x23, 0x10, 0x9e, 0x8f, 0x11, 0x13, 0x9c, 0x87 + }; + uint8_t test2[] = + { + 0xd4, 0x19, 0xba, 0xd3, 0x2d, 0x50, 0x4f, 0xb7, + 0xd4, 0x4d, 0x46, 0x0c, 0x42, 0xc5, 0x59, 0x3f, + 0xe5, 0x44, 0xfa, 0x4c, 0x13, 0x5d, 0xec, 0x31, + 0xe2, 0x1b, 0xd9, 0xab, 0xdc, 0xc2, 0x2d, 0x41 + }; + memset( in, 0, 72 ); + blake256_hash( out, in, 1 ); + v = 0; + + for( i = 0; i < 32; ++i ) + { + if ( out[i] != test1[i] ) v = 1; + } + + if ( v ) printf( "test 1 error\n" ); + + blake256_hash( out, in, 72 ); + v = 0; + + for( i = 0; i < 32; ++i ) + { + if ( out[i] != test2[i] ) v = 1; + } + + if ( v ) printf( "test 2 error\n" ); +} + +int main( int argc, char **argv ) +{ +#define BLOCK256 64 + FILE *fp; + int i, j, bytesread; + uint8_t in[BLOCK256], out[32]; + state256 S; + blake256_test(); + + for( i = 1; i < argc; ++i ) + { + fp = fopen( *( argv + i ), "r" ); + + if ( fp == NULL ) + { + printf( "Error: unable to open %s\n", *( argv + i ) ); + return 1; + } + + blake256_init( &S ); + + while( 1 ) + { + bytesread = fread( in, 1, BLOCK256, fp ); + + if ( bytesread ) + blake256_update( &S, in, bytesread ); + else + break; + } + + blake256_final( &S, out ); + + for( j = 0; j < 32; ++j ) + printf( "%02x", out[j] ); + + printf( " %s\n", *( argv + i ) ); + fclose( fp ); + } + + return 0; +} + +// Written in 2011-2012 by Dmitry Chestnykh. +// +// To the extent possible under law, the author have dedicated all copyright +// and related and neighboring rights to this software to the public domain +// worldwide. This software is distributed without any warranty. +// http://creativecommons.org/publicdomain/zero/1.0/ + +// Package blake256 implements BLAKE-256 and BLAKE-224 hash functions (SHA-3 +// candidate). +package blake256 + +import "hash" + +// The block size of the hash algorithm in bytes. +const BlockSize = 64 + +// The size of BLAKE-256 hash in bytes. +const Size = 32 + +// The size of BLAKE-224 hash in bytes. +const Size224 = 28 + +type digest struct { + hashSize int // hash output size in bits (224 or 256) + h [8]uint32 // current chain value + s [4]uint32 // salt (zero by default) + t uint64 // message bits counter + nullt bool // special case for finalization: skip counter + x [BlockSize]byte // buffer for data not yet compressed + nx int // number of bytes in buffer +} + +var ( + // Initialization values. + iv256 = [8]uint32{ + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, + 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19} + + iv224 = [8]uint32{ + 0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939, + 0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4} + + pad = [64]byte{0x80} +) + +// Reset resets the state of digest. It leaves salt intact. +func (d *digest) Reset() { + if d.hashSize == 224 { + d.h = iv224 + } else { + d.h = iv256 + } + d.t = 0 + d.nx = 0 + d.nullt = false +} + +func (d *digest) Size() int { return d.hashSize >> 3 } + +func (d *digest) BlockSize() int { return BlockSize } + +func (d *digest) Write(p []byte) (nn int, err error) { + nn = len(p) + if d.nx > 0 { + n := len(p) + if n > BlockSize-d.nx { + n = BlockSize - d.nx + } + d.nx += copy(d.x[d.nx:], p) + if d.nx == BlockSize { + block(d, d.x[:]) + d.nx = 0 + } + p = p[n:] + } + if len(p) >= BlockSize { + n := len(p) &^ (BlockSize - 1) + block(d, p[:n]) + p = p[n:] + } + if len(p) > 0 { + d.nx = copy(d.x[:], p) + } + return +} + +// Sum returns the calculated checksum. +func (d0 *digest) Sum(in []byte) []byte { + // Make a copy of d0 so that caller can keep writing and summing. + d := *d0 + + nx := uint64(d.nx) + l := d.t + nx<<3 + len := make([]byte, 8) + len[0] = byte(l >> 56) + len[1] = byte(l >> 48) + len[2] = byte(l >> 40) + len[3] = byte(l >> 32) + len[4] = byte(l >> 24) + len[5] = byte(l >> 16) + len[6] = byte(l >> 8) + len[7] = byte(l) + + if nx == 55 { + // One padding byte. + d.t -= 8 + if d.hashSize == 224 { + d.Write([]byte{0x80}) + } else { + d.Write([]byte{0x81}) + } + } else { + if nx < 55 { + // Enough space to fill the block. + if nx == 0 { + d.nullt = true + } + d.t -= 440 - nx<<3 + d.Write(pad[0 : 55-nx]) + } else { + // Need 2 compressions. + d.t -= 512 - nx<<3 + d.Write(pad[0 : 64-nx]) + d.t -= 440 + d.Write(pad[1:56]) + d.nullt = true + } + if d.hashSize == 224 { + d.Write([]byte{0x00}) + } else { + d.Write([]byte{0x01}) + } + d.t -= 8 + } + d.t -= 64 + d.Write(len) + + out := make([]byte, d.Size()) + j := 0 + for _, s := range d.h[:d.hashSize>>5] { + out[j+0] = byte(s >> 24) + out[j+1] = byte(s >> 16) + out[j+2] = byte(s >> 8) + out[j+3] = byte(s >> 0) + j += 4 + } + return append(in, out...) +} + +func (d *digest) setSalt(s []byte) { + if len(s) != 16 { + panic("salt length must be 16 bytes") + } + d.s[0] = uint32(s[0])<<24 | uint32(s[1])<<16 | uint32(s[2])<<8 | uint32(s[3]) + d.s[1] = uint32(s[4])<<24 | uint32(s[5])<<16 | uint32(s[6])<<8 | uint32(s[7]) + d.s[2] = uint32(s[8])<<24 | uint32(s[9])<<16 | uint32(s[10])<<8 | uint32(s[11]) + d.s[3] = uint32(s[12])<<24 | uint32(s[13])<<16 | uint32(s[14])<<8 | uint32(s[15]) +} + +// New returns a new hash.Hash computing the BLAKE-256 checksum. +func New() hash.Hash { + return &digest{ + hashSize: 256, + h: iv256, + } +} + +// NewSalt is like New but initializes salt with the given 16-byte slice. +func NewSalt(salt []byte) hash.Hash { + d := &digest{ + hashSize: 256, + h: iv256, + } + d.setSalt(salt) + return d +} + +// New224 returns a new hash.Hash computing the BLAKE-224 checksum. +func New224() hash.Hash { + return &digest{ + hashSize: 224, + h: iv224, + } +} + +// New224Salt is like New224 but initializes salt with the given 16-byte slice. +func New224Salt(salt []byte) hash.Hash { + d := &digest{ + hashSize: 224, + h: iv224, + } + d.setSalt(salt) + return d +} \ No newline at end of file