2
0
mirror of https://github.com/esiur/esiur-dart.git synced 2025-05-06 20:02:59 +00:00
2019-08-07 05:12:10 +03:00

161 lines
6.1 KiB
Dart

import '../../Data/DC.dart';
import '../../Data/BinaryList.dart';
import 'dart:typed_data';
class SHA256
{
static int RROT(int n, int d)
{
return ZSHIFT(n, d) | (n << (32 - d));
}
// Zero-fill right shift
static int ZSHIFT(int n, int d)
{
return (n & 0xFFFFFFFF) >> d;
}
static DC compute(DC msg)
{
/*
Note 1: All variables are 32 bit unsigned integers and addition is calculated modulo 2^32
Note 2: For each round, there is one round constant k[i] and one entry in the message schedule array w[i], 0 ≤ i ≤ 63
Note 3: The compression function uses 8 working variables, a through h
Note 4: Big-endian convention is used when expressing the constants in this pseudocode,
and when parsing message block data from bytes to words, for example,
the first word of the input message "abc" after padding is 0x61626380
*/
// Initialize hash values:
// (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
var hash = new Uint32List.fromList([0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f,
0x9b05688c, 0x1f83d9ab, 0x5be0cd19 ]);
// Initialize array of round constants:
// (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311):
var k = new Uint32List.fromList([
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 ]);
// Pre-processing:
// begin with the original message of length L bits
int L = msg.length * 8;
// append a single '1' bit
// append K '0' bits, where K is the minimum number >= 0 such that L + 1 + K + 64 is a multiple of 512
var K = 512 - ((L + 1 + 64) % 512);
if (K == 512)
K = 0;
var paddingLength = (K + 1) ~/ 8;
var paddingBytes = new DC(paddingLength);
paddingBytes[0] = 0x80;
var data = new BinaryList().addDC(msg).addDC(paddingBytes).addUint64(L).toDC();
// append L as a 64-bit big-endian integer, making the total post-processed length a multiple of 512 bits
// Process the message in successive 512-bit chunks:
// break message into 512-bit chunks
// for each chunk
for (var chunk = 0; chunk < data.length; chunk += 64)
{
// create a 64-entry message schedule array w[0..63] of 32-bit words
// (The initial values in w[0..63] don't matter, so many implementations zero them here)
// copy chunk into first 16 words w[0..15] of the message schedule array
var w = new Uint64List(64);// uint[64];
for (var i = 0; i < 16; i++)
w[i] = data.getUint32(chunk + (i * 4));
//for(var i = 16; i < 64; i++)
// w[i] = 0;
// Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array:
// for i from 16 to 63
// s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3)
// s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift 10)
// w[i] := w[i-16] + s0 + w[i-7] + s1
for (var i = 16; i < 64; i++)
{
var s0 = SHA256.RROT(w[i - 15], 7) ^ SHA256.RROT(w[i - 15], 18) ^ ZSHIFT(w[i - 15], 3);
var s1 = SHA256.RROT(w[i - 2], 17) ^ SHA256.RROT(w[i - 2], 19) ^ ZSHIFT(w[i - 2], 10);
w[i] = w[i - 16] + s0 + w[i - 7] + s1;
}
// Initialize working variables to current hash value:
var a = hash[0];
var b = hash[1];
var c = hash[2];
var d = hash[3];
var e = hash[4];
var f = hash[5];
var g = hash[6];
var h = hash[7];
// Compression function main loop:
for (var i = 0; i < 64; i++)
{
var S1 = SHA256.RROT(e, 6) ^ SHA256.RROT(e, 11) ^ SHA256.RROT(e, 25);
var ch = (e & f) ^ ((~e) & g);
var temp1 = h + S1 + ch + k[i] + w[i];
var S0 = SHA256.RROT(a, 2) ^ SHA256.RROT(a, 13) ^ SHA256.RROT(a, 22);
var maj = (a & b) ^ (a & c) ^ (b & c);
int temp2 = S0 + maj;
h = g;
g = f;
f = e;
e = ZSHIFT(d + temp1, 0);
d = c;
c = b;
b = a;
a = ZSHIFT(temp1 + temp2, 0);
}
// Add the compressed chunk to the current hash value:
hash[0] = ZSHIFT(hash[0] + a, 0);
hash[1] = ZSHIFT(hash[1] + b , 0);
hash[2] = ZSHIFT(hash[2] + c , 0);
hash[3] = ZSHIFT(hash[3] + d , 0);
hash[4] = ZSHIFT(hash[4] + e , 0);
hash[5] = ZSHIFT(hash[5] + f , 0);
hash[6] = ZSHIFT(hash[6] + g , 0);
hash[7] = ZSHIFT(hash[7] + h, 0);
}
// Produce the final hash value (big-endian):
//digest := hash := h0 append h1 append h2 append h3 append h4 append h5 append h6 append h7
var results = new BinaryList();
for (var i = 0; i < 8; i++)
results.addUint32(hash[i]);
return results.toDC();
}
}