Skip to content

Commit 37456bf

Browse files
committed
Implement bit-oriented SHA-1.
1 parent 27ccaa4 commit 37456bf

5 files changed

Lines changed: 102 additions & 0 deletions

File tree

bitarray_sha1.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright (c) 2021 Hirotsuna Mizuno. All rights reserved.
2+
// Use of this source code is governed by the MIT license that can be found in
3+
// the LICENSE file.
4+
5+
package bitarray
6+
7+
import (
8+
//nolint:gosec // intentionally provided option
9+
_ "crypto/sha1" // block()
10+
"encoding/binary"
11+
_ "unsafe" // linkname
12+
)
13+
14+
// SHA1 returns the SHA-1 checksum of the bit array. It treats the bit array as
15+
// a bit-oriented message to compute the checksum as defined in RFC 3174.
16+
func (ba *BitArray) SHA1() [20]byte {
17+
nBits := ba.Len()
18+
buf := NewBuffer((nBits + 1 + 64 + 511) &^ 511)
19+
buf.PutBitArrayAt(0, ba)
20+
buf.PutBitAt(nBits, 1)
21+
binary.BigEndian.PutUint64(buf.b[len(buf.b)-8:], uint64(nBits))
22+
23+
d := &sha1Digest{}
24+
sha1Reset(d)
25+
sha1Block(d, buf.b)
26+
27+
var sha1 [20]byte
28+
for i := 0; i < 5; i++ {
29+
binary.BigEndian.PutUint32(sha1[i<<2:], d.h[i])
30+
}
31+
32+
return sha1
33+
}
34+
35+
// crypto/sha1.digest
36+
// TODO: if possible, use crypto/sha1.digest directly
37+
type sha1Digest struct {
38+
h [5]uint32
39+
x [64]byte //nolint:structcheck,unused // for Reset()
40+
nx int //nolint:structcheck,unused // for Reset()
41+
len uint64 //nolint:structcheck,unused // for Reset()
42+
}
43+
44+
//go:linkname sha1Block crypto/sha1.block
45+
func sha1Block(*sha1Digest, []byte)
46+
47+
//go:linkname sha1Reset crypto/sha1.(*digest).Reset
48+
func sha1Reset(*sha1Digest)

bitarray_sha1_example_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright (c) 2021 Hirotsuna Mizuno. All rights reserved.
2+
// Use of this source code is governed by the MIT license that can be found in
3+
// the LICENSE file.
4+
5+
package bitarray_test
6+
7+
import (
8+
"fmt"
9+
10+
"github.com/tunabay/go-bitarray"
11+
)
12+
13+
func ExampleBitArray_SHA1() {
14+
ba1 := bitarray.MustParse("01")
15+
ba2 := bitarray.MustParse("01001")
16+
17+
fmt.Printf("%x\n", ba1.SHA1())
18+
fmt.Printf("%x\n", ba2.SHA1())
19+
20+
// Output:
21+
// ec6b39952e1a3ec3ab3507185cf756181c84bbe2
22+
// 3320540d1c28b96ddd03eee1b186a8f2ae883fbe
23+
}

bitarray_sha1_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) 2021 Hirotsuna Mizuno. All rights reserved.
2+
// Use of this source code is governed by the MIT license that can be found in
3+
// the LICENSE file.
4+
5+
package bitarray_test
6+
7+
import (
8+
"bytes"
9+
"testing"
10+
)
11+
12+
func TestBitArray_SHA1_cavp(t *testing.T) {
13+
test := func(name string) {
14+
tcs, err := cavpTestCases(name)
15+
if err != nil {
16+
t.Fatalf("failed to load test cases: %s: %s", name, err)
17+
}
18+
for i, tc := range tcs {
19+
got := tc.ba.SHA1()
20+
if !bytes.Equal(got[:], tc.md) {
21+
t.Errorf("unexpected hash: %s: #%d", name, i)
22+
t.Logf("mlen: %d", tc.ba.Len())
23+
t.Logf(" msg: %#b", tc.ba)
24+
t.Logf(" got: %X", got)
25+
t.Logf("want: %X", tc.md)
26+
}
27+
}
28+
}
29+
test("SHA1ShortMsg")
30+
test("SHA1LongMsg")
31+
}

testdata/SHA1LongMsg.rsp.bz2

1.62 MB
Binary file not shown.

testdata/SHA1ShortMsg.rsp.bz2

29.4 KB
Binary file not shown.

0 commit comments

Comments
 (0)