-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathwots.go
More file actions
154 lines (137 loc) · 4.48 KB
/
Copy pathwots.go
File metadata and controls
154 lines (137 loc) · 4.48 KB
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package mbpqs
// The Winternitz One-Time Signature scheme as used by MBPQS.
// Generate WOTS+ secret key
func (ctx *Context) genWotsSk(pad scratchPad, ph precomputedHashes,
addr address, out []byte) {
var i uint32
addr.setChain(0)
addr.setHash(0)
addr.setKeyAndMask(0)
buf := pad.wotsSkSeedBuf()
ph.prfAddrSkSeedInto(pad, addr, buf)
for i = 0; i < ctx.wotsLen; i++ {
ctx.prfUint64Into(pad, uint64(i), buf, out[i*ctx.params.n:])
}
}
// Converts a message into positions on the WOTS+ chains, which
// are called "chain lengths".
func (ctx *Context) wotsChainLengths(msg []byte) []uint8 {
ret := make([]uint8, ctx.wotsLen)
// compute the chain lengths for the message itself
ctx.toBaseW(msg, ret[:ctx.wotsLen1])
// compute the checksum
var csum uint32 // = 0 init
for i := 0; i < int(ctx.wotsLen1); i++ {
csum += uint32(ctx.params.w) - 1 - uint32(ret[i])
}
csum = csum << (8 - ((ctx.wotsLen2 * uint32(ctx.wotsLogW)) % 8))
// put checksum in buffer
ctx.toBaseW(
encodeUint64(
uint64(csum),
int((ctx.wotsLen2*uint32(ctx.wotsLogW)+7)/8)),
ret[ctx.wotsLen1:])
return ret
}
// Converts the given array of bytes into base w for the WOTS+ one-time
// signature scheme. Only works if LogW divides into 8.
func (ctx *Context) toBaseW(input []byte, output []uint8) {
if ctx.params.w == 256 {
copy(output, input)
return
}
var in uint32 // = 0 init
var out uint32 // = 0 init
var total uint8
var bits uint8
for consumed := 0; consumed < len(output); consumed++ {
if bits == 0 {
total = input[in]
in++
bits = 8
}
bits -= ctx.wotsLogW
output[out] = uint8(uint16(total>>bits) & (ctx.params.w - 1))
out++
}
}
// Compute the (start + steps)th value in the WOTS+ chain, given
// the start'th value in the chain.
func (ctx *Context) wotsGenChainInto(pad scratchPad, in []byte,
start, steps uint16, ph precomputedHashes, addr address, out []byte) {
copy(out, in)
var i uint16
for i = start; i < (start+steps) && (i < ctx.params.w); i++ {
addr.setHash(uint32(i))
ctx.fInto(pad, out, ph, addr, out)
}
}
// Generate a WOTS+ public key from secret key seed.
func (ctx *Context) wotsPkGen(pad scratchPad, ph precomputedHashes,
addr address) []byte {
ret := make([]byte, ctx.wotsLen*ctx.params.n)
ctx.wotsPkGenInto(pad, ph, addr, ret)
return ret
}
// Generate a WOTS+ public key from secret key seed.
func (ctx *Context) wotsPkGenInto(pad scratchPad, ph precomputedHashes,
addr address, out []byte) {
ctx.genWotsSk(pad, ph, addr, out)
var i uint32
for i = 0; i < ctx.wotsLen; i++ {
addr.setChain(uint32(i))
ctx.wotsGenChainInto(pad, out[ctx.params.n*i:ctx.params.n*(i+1)],
0, ctx.params.w-1, ph, addr,
out[ctx.params.n*i:ctx.params.n*(i+1)])
}
}
// Create a WOTS+ signature of a n-byte message
func (ctx *Context) wotsSign(pad scratchPad, msg, pubSeed, skSeed []byte,
addr address) []byte {
ret := make([]byte, ctx.wotsSigBytes)
ctx.wotsSignInto(pad, msg, ctx.precomputeHashes(pubSeed, skSeed), addr, ret)
return ret
}
// Create a WOTS+ signature of a n-byte message
func (ctx *Context) wotsSignInto(pad scratchPad, msg []byte,
ph precomputedHashes, addr address, wotsSig []byte) {
lengths := ctx.wotsChainLengths(msg)
ctx.genWotsSk(pad, ph, addr, wotsSig)
var i uint32
for i = 0; i < ctx.wotsLen; i++ {
addr.setChain(uint32(i))
ctx.wotsGenChainInto(pad, wotsSig[ctx.params.n*i:ctx.params.n*(i+1)],
0, uint16(lengths[i]), ph, addr,
wotsSig[ctx.params.n*i:ctx.params.n*(i+1)])
}
}
// Computes the public key from a message and its WOTS+ signature and
// stores it in the provided buffer.
func (ctx *Context) wotsPkFromSigInto(pad scratchPad, sig, msg []byte,
ph precomputedHashes, addr address, pk []byte) {
lengths := ctx.wotsChainLengths(msg)
var i uint32
for i = 0; i < ctx.wotsLen; i++ {
addr.setChain(uint32(i))
ctx.wotsGenChainInto(pad, sig[ctx.params.n*i:ctx.params.n*(i+1)],
uint16(lengths[i]), ctx.params.w-1-uint16(lengths[i]),
ph, addr, pk[ctx.params.n*i:ctx.params.n*(i+1)])
}
}
// Returns the public key from a message and its WOTS+ signature.
func (ctx *Context) wotsPkFromSig(pad scratchPad, sig, msg []byte,
ph precomputedHashes, addr address) []byte {
pk := make([]byte, ctx.params.n*ctx.wotsLen)
ctx.wotsPkFromSigInto(pad, sig, msg, ph, addr, pk)
return pk
}
// This method exists only for testing purposes!
func (ctx *Context) getWotsSeed(pad scratchPad, ph precomputedHashes,
addr address) []byte {
addr.setChain(0)
addr.setHash(0)
addr.setKeyAndMask(0)
ret := make([]byte, ctx.params.n)
ph.prfAddrSkSeedInto(pad, addr, ret)
return ret
}