Permalink
Browse files

examples/sha1: implement full hash and test

  • Loading branch information...
mmcloughlin committed Dec 22, 2018
1 parent f464082 commit 1ce7acee1d2d0488155909e2c761970f91ea1e03
Showing with 83 additions and 19 deletions.
  1. +5 −5 examples/sha1/asm.go
  2. +44 −0 examples/sha1/sha1.go
  3. +34 −14 examples/sha1/sha1_test.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,15 +104,15 @@ 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)
XORL(d, r)
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)
@@ -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
}
@@ -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}
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"},
}
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)
}
}
}

for i := 0; i < 5; i++ {
log.Printf("h[%d] = %08x", i, h[i])
func TestCmp(t *testing.T) {
if err := quick.CheckEqual(Sum, sha1.Sum, nil); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(expect, h) {
t.Fatal("incorrect hash")
}

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)
}
}
}

0 comments on commit 1ce7ace

Please sign in to comment.