// X10 Version Author: J. A. Kuehn, Oak Ridge National Laboratory // some of this derived from brg_sha1 public final class SHA1compiler { // internal constants private final static int SHA1_DIGEST_SIZE = 20; private final static int SHA1_BLOCK_SIZE = 64; private final static int SHA1_MASK = SHA1_BLOCK_SIZE - 1; // internal rng state private int[] digest = new int[SHA1_DIGEST_SIZE/4]; // 160 bit internal representation private int[] msgblock = new int[SHA1_BLOCK_SIZE/4]; // 64 byte internal working buffer private long count = 0; // 64 bit counter of bytes processed SHA1compiler() { digest[0] = (int)0x67452301l; digest[1] = (int)0xefcdab89l; digest[2] = (int)0x98badcfel; digest[3] = (int)0x10325476l; digest[4] = (int)0xc3d2e1f0l; } public final void hash(byte[] data, int length) { int bp = 0; // byte position in data[] int pos = (int)(count & SHA1_MASK); // byte position in msgblock int wpos = pos>>>2; // word position in msgblock int space = SHA1_BLOCK_SIZE - pos; // bytes left in msgblock int len = length; // number of bytes left to process in data count += len; // total number of bytes processed since begin // for UTS our data should always show up in 4 byte multiples // assert (0 == (3&pos)) : "\n\nASSERT\tnot a multiple of 4.\n\tpos="+pos+"\n\n"; // assert (0 == (3&len)) : "\n\nASSERT\tnot a multiple of 4.\n\tlen="+len+"\n\n"; // assert (0 == (3&space)) : "\n\nASSERT\tnot a multiple of 4.\n\tspace="+space+"\n\n"; // assert (0 == (3&count)) : "\n\nASSERT\tnot a multple of 4.\n\tcount="+count+"\n\n"; while(len >= space) { for(; wpos < (SHA1_BLOCK_SIZE>>>2); bp+=4) { // "int" aligned (byte)memory to (int)memory copy msgblock[wpos++] = (((int)data[bp ]&0xFF)<<24) | (((int)data[bp+1]&0xFF)<<16) | (((int)data[bp+2]&0xFF)<< 8) | ((int)data[bp+3]&0xFF) ; } compile(); len -= space; space = SHA1_BLOCK_SIZE; wpos = 0; } for(; bp < length; bp+=4) { // this is the "int" aligned (byte)memory to (int)memory copy msgblock[wpos++] = (((int)data[bp ]&0xFF)<<24) | (((int)data[bp+1]&0xFF)<<16) | (((int)data[bp+2]&0xFF)<< 8) | (((int)data[bp+3]&0xFF)); } // assert (((SHA1_MASK&count)>>>2) == wpos) : "\n\nASSERT\twpos alignment\n\twpos="+wpos+"\n\tcount/4="+(count/4)+"\n\n"; } public final void digest(byte[] output) { int i = (int)(count & SHA1_MASK); // how many bytes already in msgblock[]? msgblock[i >> 2] &= (int)(0xffffff80l << 8 * (~i & 3)); msgblock[i >> 2] |= (int)(0x00000080l << 8 * (~i & 3)); if(i > SHA1_BLOCK_SIZE - 9) { if(i < 60) msgblock[15] = 0; compile(); i = 0; } else { i = (i >> 2) + 1; } while(i < 14) msgblock[i++] = 0; msgblock[14] = (int)((count >> 29)); msgblock[15] = (int)((count << 3)); compile(); // THIS call accounts for 50% of the program execution time... for(i = 0; i < SHA1_DIGEST_SIZE; ++i) output[i] = (byte)(digest[i >> 2] >> (8 * (~i & 3))); } // bit twiddling ahead #define rotl32(x,n) (((x) << (n)) | ((x) >>> (32 - (n)))) #define rotr32(x,n) (((x) >>> (n)) | ((x) << (32 - (n)))) #define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) #define parity(x,y,z) ((x) ^ (y) ^ (z)) #define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y)))) #define q(v,n) v##n #define one_cycle(v,a,b,c,d,e,f,k,h) \ q(v,e) += rotr32(q(v,a),27) + f(q(v,b),q(v,c),q(v,d)) + k + h; \ q(v,b) = rotr32(q(v,b), 2) #define five_cycle(v,f,k,i) \ one_cycle(v, 0,1,2,3,4, f,k,hf(i )); \ one_cycle(v, 4,0,1,2,3, f,k,hf(i+1)); \ one_cycle(v, 3,4,0,1,2, f,k,hf(i+2)); \ one_cycle(v, 2,3,4,0,1, f,k,hf(i+3)); \ one_cycle(v, 1,2,3,4,0, f,k,hf(i+4)) private final void compile() { int v0, v1, v2, v3, v4; v0 = digest[0]; v1 = digest[1]; v2 = digest[2]; v3 = digest[3]; v4 = digest[4]; #define hf(i) msgblock[i] five_cycle(v, ch, (int)0x5a827999l, 0); five_cycle(v, ch, (int)0x5a827999l, 5); five_cycle(v, ch, (int)0x5a827999l, 10); one_cycle(v,0,1,2,3,4, ch, (int)0x5a827999l, hf(15)); #undef hf #define hf(i) (msgblock[(i) & 15] = rotl32( msgblock[((i) + 13) & 15] ^ msgblock[((i) + 8) & 15] ^ msgblock[((i) + 2) & 15] ^ msgblock[(i) & 15], 1)) one_cycle(v,4,0,1,2,3, ch, (int)0x5a827999l, hf(16)); one_cycle(v,3,4,0,1,2, ch, (int)0x5a827999l, hf(17)); one_cycle(v,2,3,4,0,1, ch, (int)0x5a827999l, hf(18)); one_cycle(v,1,2,3,4,0, ch, (int)0x5a827999l, hf(19)); five_cycle(v, parity, (int)0x6ed9eba1l, 20); five_cycle(v, parity, (int)0x6ed9eba1l, 25); five_cycle(v, parity, (int)0x6ed9eba1l, 30); five_cycle(v, parity, (int)0x6ed9eba1l, 35); five_cycle(v, maj, (int)0x8f1bbcdcl, 40); five_cycle(v, maj, (int)0x8f1bbcdcl, 45); five_cycle(v, maj, (int)0x8f1bbcdcl, 50); five_cycle(v, maj, (int)0x8f1bbcdcl, 55); five_cycle(v, parity, (int)0xca62c1d6l, 60); five_cycle(v, parity, (int)0xca62c1d6l, 65); five_cycle(v, parity, (int)0xca62c1d6l, 70); five_cycle(v, parity, (int)0xca62c1d6l, 75); digest[0] += v0; digest[1] += v1; digest[2] += v2; digest[3] += v3; digest[4] += v4; } public static void main(String[] args) { byte[] data1 = {(byte)0x1,(byte)0x2,(byte)0x3,(byte)0x4}; byte[] data2 = {(byte)0xf1,(byte)0xf2,(byte)0xf3,(byte)0xf4}; byte[] digest = new byte[20]; /////////////////////////////////////////////////////////////// // test ctor System.out.println("init"); SHA1compiler sha = new SHA1compiler(); sha.showdigest(); /////////////////////////////////////////////////////////////// // set msgblock System.out.println("message"); for(int i=0; i