-
Notifications
You must be signed in to change notification settings - Fork 2
/
hash.go
105 lines (88 loc) · 2.11 KB
/
hash.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package gonut
import "unsafe"
// donut/hash.h
const (
MARU_MAX_STR = 64
MARU_BLK_LEN = 16
MARU_HASH_LEN = 8
MARU_IV_LEN = MARU_HASH_LEN
)
var (
MARU_CRYPT = Speck
)
// ROTR32
// donut/hash.h
// #define ROTR32(v,n)(((v)>>(n))|((v)<<(32-(n))))
func ROTR32(v uint32, n uint32) uint32 {
return ((v) >> (n)) | ((v) << (32 - (n)))
}
// Speck SPECK-64/128
// donut/hash.c
// static uint64_t speck(void *mk, uint64_t p) { ... }
func Speck(mk [MARU_BLK_LEN]byte, p uint64) uint64 {
var k [4]uint32
var x [8]uint8
w := (*[2]uint32)(unsafe.Pointer(&x))
q := (*uint64)(unsafe.Pointer(&x))
// copy 64-bit plaintext to local buffer
*q = p
// copy 128-bit master key to local buffer
for i := 0; i < 4; i++ {
k[i] = (*[MARU_BLK_LEN / 4]uint32)(unsafe.Pointer(&mk))[i]
}
for i := uint32(0); i < 27; i++ {
// encrypt 64-bit plaintext
w[0] = (ROTR32(w[0], 8) + w[1]) ^ k[0]
w[1] = ROTR32(w[1], 29) ^ w[0]
// create next 32-bit subkey
t := k[3]
k[3] = (ROTR32(k[1], 8) + k[0]) ^ i
k[0] = ROTR32(k[0], 29) ^ k[3]
k[1] = k[2]
k[2] = t
}
// return 64-bit ciphertext
return *q
}
// Maru
// donut/hash.c
// uint64_t maru(const void *input, uint64_t iv) { ... }
func Maru(input []byte, iv uint64) uint64 {
var m [MARU_BLK_LEN]uint8
b := (*[MARU_BLK_LEN]uint8)(unsafe.Pointer(&m))
w := (*[MARU_BLK_LEN / 4]uint32)(unsafe.Pointer(&m))
// set H to initial value
h := iv
for idx, length, end := 0, 0, false; !end; {
// end of string or max len?
if length == len(input) || length == MARU_MAX_STR {
// zero remainder of M
copy(b[idx:], make([]uint8, MARU_BLK_LEN-idx))
// store the end bit
b[idx] = 0x80
// have we space in M for api length?
if idx >= MARU_BLK_LEN-4 {
// no, update H with E
h ^= MARU_CRYPT(m, h)
// zero M
m = [MARU_BLK_LEN]byte{0}
}
// store total length in bits
w[MARU_BLK_LEN/4-1] = uint32(length * 8)
idx = MARU_BLK_LEN
end = true
} else {
// store character from api string
b[idx] = input[length]
idx++
length++
}
if idx == MARU_BLK_LEN {
// update H with E
h ^= MARU_CRYPT(m, h)
// reset idx
idx = 0
}
}
return h
}