diff --git a/hash/sha2/compress.go b/hash/sha2/compress.go index c95cda2..927bcd6 100644 --- a/hash/sha2/compress.go +++ b/hash/sha2/compress.go @@ -4,6 +4,10 @@ func rotl32(count uint32, val uint32) uint32 { return (val << count) | (val >> (32 - count)) } +func rotr32(count uint32, val uint32) uint32 { + return (val >> count) | (val << (32 - count)) +} + // compression func p0(X uint32) uint32 { return X ^ rotl32(9, X) ^ rotl32(17, X) @@ -14,12 +18,22 @@ func p1(X uint32) uint32 { return X ^ rotl32(15, X) ^ rotl32(23, X) } -func ff1(X uint32, Y uint32, Z uint32) uint32 { - return (X & Y) | ((X | Y) & Z) + +// Choose bitwise between A or B controlled by C. A if C=1 otherwise B +// Optimized as per, "Hackers Delight" (7-1, MUX operation), can be used +// to reduce number of operations. +func ch(M uint32, A uint32, B uint32) uint32 { + return ((A ^ B) & M) ^ B } -func gg1(X uint32, Y uint32, Z uint32) uint32 { - return (X & Y) ^ ((^X) & Z) // Can be also (Z ^ (X & (Y ^ Z))) +// Majority function - takes the majority value as the final result. If two +// or three of the variables are 1, then the result is 1, otherwise 0. +func maj(X uint32, Y uint32, Z uint32) uint32 { + // Y^Z works as a mask. If mask is 0, then majority is dictated by + // value of either Y or Z (doesn't matter, as they are the same, but we + // don't know if result is 0 or 1). Otherwise Y!=Z and results is + // going to dicated by X. + return ch(Y^Z, X, Y) } func r1( @@ -43,8 +57,8 @@ func r2( A12 := rotl32(12, A) SS1 := rotl32(7, A12+E+TJ) - TT1 := ff1(A, *B, C) + *D + (SS1 ^ A12) + Wj - TT2 := gg1(E, *F, G) + *H + SS1 + Wi + TT1 := maj(A, *B, C) + *D + (SS1 ^ A12) + Wj + TT2 := ch(E, *F, G) + *H + SS1 + Wi *B = rotl32(9, *B) *D = TT1 diff --git a/hash/sha2/sha2_test.go b/hash/sha2/sha2_test.go index 367ee04..92c3ed6 100644 --- a/hash/sha2/sha2_test.go +++ b/hash/sha2/sha2_test.go @@ -36,8 +36,12 @@ func TestSHA256OfficialVectors(t *testing.T) { [32]byte{ 0xe3,0xb0,0xc4,0x42,0x98,0xfc,0x1c,0x14,0x9a,0xfb,0xf4,0xc8,0x99,0x6f,0xb9,0x24,0x27,0xae,0x41,0xe4,0x64,0x9b,0x93,0x4c,0xa4,0x95,0x99,0x1b,0x78,0x52,0xb8,0x55}, }, + { + []byte{0x61}, + [32]byte{ + 0xca,0x97,0x81,0x12,0xca,0x1b,0xbd,0xca,0xfa,0xc2,0x31,0xb3,0x9a,0x23,0xdc,0x4d,0xa7,0x86,0xef,0xf8,0x14,0x7c,0x4e,0x72,0xb9,0x80,0x77,0x85,0xaf,0xee,0x48,0xbb}, + }, /* - // draft-shen-sha2-hash-01: Example 2 { []byte{ 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x63, 0x64, @@ -48,7 +52,6 @@ func TestSHA256OfficialVectors(t *testing.T) { 0xde, 0xbe, 0x9f, 0xf9, 0x22, 0x75, 0xb8, 0xa1, 0x38, 0x60, 0x48, 0x89, 0xc1, 0x8e, 0x5a, 0x4d, 0x6f, 0xdb, 0x70, 0xe5, 0x38, 0x7e, 0x57, 0x65, 0x29, 0x3d, 0xcb, 0xa3, 0x9c, 0x0c, 0x57, 0x32}, }, - // B.1. GB/T 32918.2-2016 A.2 Example 1 { []byte{ 0x00, 0x90, 0x41, 0x4C, 0x49, 0x43, 0x45, 0x31, 0x32, 0x33, 0x40, 0x59, 0x41, 0x48, 0x4F, 0x4F,