Skip to content

Commit 27ccaa4

Browse files
committed
Implement bit-oriented SHA-256 family.
1 parent c06ea42 commit 27ccaa4

7 files changed

Lines changed: 151 additions & 0 deletions

bitarray_sha256.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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+
_ "crypto/sha256" // block()
9+
"encoding/binary"
10+
_ "unsafe" // linkname
11+
)
12+
13+
// SHA256 returns the SHA-256 checksum of the bit array. It treats the bit array
14+
// as a bit-oriented message to compute the checksum as defined in FIPS 180-4.
15+
func (ba *BitArray) SHA256() (d256 [32]byte) {
16+
return ba.sha256CheckSum(false)
17+
}
18+
19+
// SHA224 returns the SHA-224 checksum of the bit array. It treats the bit array
20+
// as a bit-oriented message to compute the checksum as defined in FIPS 180-4.
21+
func (ba *BitArray) SHA224() (d224 [28]byte) {
22+
d256 := ba.sha256CheckSum(true)
23+
copy(d224[:], d256[:])
24+
return
25+
}
26+
27+
func (ba *BitArray) sha256CheckSum(is224 bool) [32]byte {
28+
nBits := ba.Len()
29+
buf := NewBuffer((nBits + 1 + 64 + 511) &^ 511)
30+
buf.PutBitArrayAt(0, ba)
31+
buf.PutBitAt(nBits, 1)
32+
binary.BigEndian.PutUint64(buf.b[len(buf.b)-8:], uint64(nBits))
33+
34+
d := &sha256Digest{is224: is224}
35+
sha256Reset(d)
36+
sha256Block(d, buf.b)
37+
38+
n := 8
39+
if is224 {
40+
n = 7
41+
}
42+
var d256 [32]byte
43+
for i := 0; i < n; i++ {
44+
binary.BigEndian.PutUint32(d256[i<<2:], d.h[i])
45+
}
46+
47+
return d256
48+
}
49+
50+
// crypto/sha256.digest
51+
// TODO: if possible, use crypto/sha256.digest directly
52+
type sha256Digest struct {
53+
h [8]uint32
54+
x [64]byte //nolint:structcheck,unused // for Reset()
55+
nx int //nolint:structcheck,unused // for Reset()
56+
len uint64 //nolint:structcheck,unused // for Reset()
57+
is224 bool
58+
}
59+
60+
//go:linkname sha256Block crypto/sha256.block
61+
func sha256Block(*sha256Digest, []byte)
62+
63+
//go:linkname sha256Reset crypto/sha256.(*digest).Reset
64+
func sha256Reset(*sha256Digest)

bitarray_sha256_example_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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_SHA256() {
14+
ba1 := bitarray.MustParse("011")
15+
ba2 := bitarray.MustParse("010000")
16+
17+
fmt.Printf("%x\n", ba1.SHA256())
18+
fmt.Printf("%x\n", ba2.SHA256())
19+
20+
// Output:
21+
// 1f7794d4b0b67d3a6edcd17aba2144a95828032f7943ed26bf0c7c7628945f48
22+
// 5ef0224f79737bda30562831152184b939cc43fcd40d09f4945e081a39c6d542
23+
}
24+
25+
func ExampleBitArray_SHA224() {
26+
ba1 := bitarray.MustParse("10")
27+
ba2 := bitarray.MustParse("100")
28+
29+
fmt.Printf("%x\n", ba1.SHA224())
30+
fmt.Printf("%x\n", ba2.SHA224())
31+
32+
// Output:
33+
// ef9c947a47bb9311a0f2b8939cfc12090554868b3b64d8f71e6442f3
34+
// 4f2ec61c914dce56c3fe5067aa184125ab126c39edb8bf64f58bdccd
35+
}

bitarray_sha256_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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_SHA256_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.SHA256()
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("SHA256ShortMsg")
30+
test("SHA256LongMsg")
31+
}
32+
33+
func TestBitArray_SHA224_cavp(t *testing.T) {
34+
test := func(name string) {
35+
tcs, err := cavpTestCases(name)
36+
if err != nil {
37+
t.Fatalf("failed to load test cases: %s: %s", name, err)
38+
}
39+
for i, tc := range tcs {
40+
got := tc.ba.SHA224()
41+
if !bytes.Equal(got[:], tc.md) {
42+
t.Errorf("unexpected hash: %s: #%d", name, i)
43+
t.Logf("mlen: %d", tc.ba.Len())
44+
t.Logf(" msg: %#b", tc.ba)
45+
t.Logf(" got: %X", got)
46+
t.Logf("want: %X", tc.md)
47+
}
48+
}
49+
}
50+
test("SHA224ShortMsg")
51+
test("SHA224LongMsg")
52+
}

testdata/SHA224LongMsg.rsp.bz2

1.62 MB
Binary file not shown.

testdata/SHA224ShortMsg.rsp.bz2

33.6 KB
Binary file not shown.

testdata/SHA256LongMsg.rsp.bz2

1.63 MB
Binary file not shown.

testdata/SHA256ShortMsg.rsp.bz2

35.6 KB
Binary file not shown.

0 commit comments

Comments
 (0)