diff --git a/examples/sha1/asm.go b/examples/sha1/asm.go index 8888ad0..6ad6581 100644 --- a/examples/sha1/asm.go +++ b/examples/sha1/asm.go @@ -5,7 +5,7 @@ package main import ( . "github.com/mmcloughlin/avo/build" . "github.com/mmcloughlin/avo/operand" - "github.com/mmcloughlin/avo/reg" + . "github.com/mmcloughlin/avo/reg" ) func main() { @@ -37,7 +37,7 @@ func main() { // Generate round updates. quarter := []struct { - F func(reg.Register, reg.Register, reg.Register) reg.Register + F func(Register, Register, Register) Register K uint32 }{ {choose, 0x5a827999}, @@ -95,7 +95,7 @@ func main() { Generate() } -func choose(b, c, d reg.Register) reg.Register { +func choose(b, c, d Register) Register { r := GP32v() MOVL(d, r) XORL(c, r) @@ -104,7 +104,7 @@ func choose(b, c, d reg.Register) reg.Register { return r } -func xor(b, c, d reg.Register) reg.Register { +func xor(b, c, d Register) Register { r := GP32v() MOVL(b, r) XORL(c, r) @@ -112,7 +112,7 @@ func xor(b, c, d reg.Register) reg.Register { return r } -func majority(b, c, d reg.Register) reg.Register { +func majority(b, c, d Register) Register { t, r := GP32v(), GP32v() MOVL(b, t) ORL(c, t) diff --git a/examples/sha1/sha1.go b/examples/sha1/sha1.go new file mode 100644 index 0000000..a1159fd --- /dev/null +++ b/examples/sha1/sha1.go @@ -0,0 +1,44 @@ +package sha1 + +import ( + "encoding/binary" +) + +const ( + Size = 20 + BlockSize = 64 +) + +func Sum(data []byte) [Size]byte { + n := len(data) + h := [5]uint32{0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0} + + // Consume full blocks. + for len(data) >= BlockSize { + block(&h, data) + data = data[BlockSize:] + } + + // Final block. + tmp := make([]byte, BlockSize) + copy(tmp[:], data) + tmp[len(data)] = 0x80 + + if len(data) >= 56 { + block(&h, tmp) + for i := 0; i < BlockSize; i++ { + tmp[i] = 0 + } + } + + binary.BigEndian.PutUint64(tmp[56:], uint64(8*n)) + block(&h, tmp) + + // Write into byte array. + var digest [Size]byte + for i := 0; i < 5; i++ { + binary.BigEndian.PutUint32(digest[4*i:], h[i]) + } + + return digest +} diff --git a/examples/sha1/sha1_test.go b/examples/sha1/sha1_test.go index 892762f..b06fd2a 100644 --- a/examples/sha1/sha1_test.go +++ b/examples/sha1/sha1_test.go @@ -1,26 +1,46 @@ package sha1 import ( - "log" - "reflect" + "bytes" + "crypto/sha1" + "encoding/hex" "testing" + "testing/quick" ) //go:generate go run asm.go -out sha1.s -stubs stub.go -func TestEmptyString(t *testing.T) { - h := [...]uint32{0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0} - m := make([]byte, 64) - m[0] = 0x80 - - block(&h, m) - - expect := [...]uint32{0xda39a3ee, 0x5e6b4b0d, 0x3255bfef, 0x95601890, 0xafd80709} - - for i := 0; i < 5; i++ { - log.Printf("h[%d] = %08x", i, h[i]) +func TestVectors(t *testing.T) { + cases := []struct { + Data string + HexDigest string + }{ + {"", "da39a3ee5e6b4b0d3255bfef95601890afd80709"}, + {"The quick brown fox jumps over the lazy dog", "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"}, + {"The quick brown fox jumps over the lazy cog", "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3"}, } - if !reflect.DeepEqual(expect, h) { - t.Fatal("incorrect hash") + for _, c := range cases { + digest := Sum([]byte(c.Data)) + got := hex.EncodeToString(digest[:]) + if got != c.HexDigest { + t.Errorf("Sum(%#v) = %s; expect %s", c.Data, got, c.HexDigest) + } + } +} + +func TestCmp(t *testing.T) { + if err := quick.CheckEqual(Sum, sha1.Sum, nil); err != nil { + t.Fatal(err) + } +} + +func TestLengths(t *testing.T) { + data := make([]byte, BlockSize) + for n := 0; n <= BlockSize; n++ { + got := Sum(data[:n]) + expect := sha1.Sum(data[:n]) + if !bytes.Equal(got[:], expect[:]) { + t.Errorf("failed on length %d", n) + } } }