OSDN Git Service

Merge pull request #41 from Bytom/dev
[bytom/vapor.git] / vendor / github.com / minio / blake2b-simd / blake2b.go
1 // Written in 2012 by Dmitry Chestnykh.
2 //
3 // To the extent possible under law, the author have dedicated all copyright
4 // and related and neighboring rights to this software to the public domain
5 // worldwide. This software is distributed without any warranty.
6 // http://creativecommons.org/publicdomain/zero/1.0/
7
8 // Package blake2b implements BLAKE2b cryptographic hash function.
9 package blake2b
10
11 import (
12         "encoding/binary"
13         "errors"
14         "hash"
15 )
16
17 const (
18         BlockSize  = 128 // block size of algorithm
19         Size       = 64  // maximum digest size
20         SaltSize   = 16  // maximum salt size
21         PersonSize = 16  // maximum personalization string size
22         KeySize    = 64  // maximum size of key
23 )
24
25 type digest struct {
26         h  [8]uint64       // current chain value
27         t  [2]uint64       // message bytes counter
28         f  [2]uint64       // finalization flags
29         x  [BlockSize]byte // buffer for data not yet compressed
30         nx int             // number of bytes in buffer
31
32         ih         [8]uint64       // initial chain value (after config)
33         paddedKey  [BlockSize]byte // copy of key, padded with zeros
34         isKeyed    bool            // indicates whether hash was keyed
35         size       uint8           // digest size in bytes
36         isLastNode bool            // indicates processing of the last node in tree hashing
37 }
38
39 // Initialization values.
40 var iv = [8]uint64{
41         0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
42         0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
43         0x510e527fade682d1, 0x9b05688c2b3e6c1f,
44         0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
45 }
46
47 // Config is used to configure hash function parameters and keying.
48 // All parameters are optional.
49 type Config struct {
50         Size   uint8  // digest size (if zero, default size of 64 bytes is used)
51         Key    []byte // key for prefix-MAC
52         Salt   []byte // salt (if < 16 bytes, padded with zeros)
53         Person []byte // personalization (if < 16 bytes, padded with zeros)
54         Tree   *Tree  // parameters for tree hashing
55 }
56
57 // Tree represents parameters for tree hashing.
58 type Tree struct {
59         Fanout        uint8  // fanout
60         MaxDepth      uint8  // maximal depth
61         LeafSize      uint32 // leaf maximal byte length (0 for unlimited)
62         NodeOffset    uint64 // node offset (0 for first, leftmost or leaf)
63         NodeDepth     uint8  // node depth (0 for leaves)
64         InnerHashSize uint8  // inner hash byte length
65         IsLastNode    bool   // indicates processing of the last node of layer
66 }
67
68 var (
69         defaultConfig = &Config{Size: Size}
70         config256     = &Config{Size: 32}
71 )
72
73 func verifyConfig(c *Config) error {
74         if c.Size > Size {
75                 return errors.New("digest size is too large")
76         }
77         if len(c.Key) > KeySize {
78                 return errors.New("key is too large")
79         }
80         if len(c.Salt) > SaltSize {
81                 // Smaller salt is okay: it will be padded with zeros.
82                 return errors.New("salt is too large")
83         }
84         if len(c.Person) > PersonSize {
85                 // Smaller personalization is okay: it will be padded with zeros.
86                 return errors.New("personalization is too large")
87         }
88         if c.Tree != nil {
89                 if c.Tree.Fanout == 1 {
90                         return errors.New("fanout of 1 is not allowed in tree mode")
91                 }
92                 if c.Tree.MaxDepth < 2 {
93                         return errors.New("incorrect tree depth")
94                 }
95                 if c.Tree.InnerHashSize < 1 || c.Tree.InnerHashSize > Size {
96                         return errors.New("incorrect tree inner hash size")
97                 }
98         }
99         return nil
100 }
101
102 // New returns a new hash.Hash configured with the given Config.
103 // Config can be nil, in which case the default one is used, calculating 64-byte digest.
104 // Returns non-nil error if Config contains invalid parameters.
105 func New(c *Config) (hash.Hash, error) {
106         if c == nil {
107                 c = defaultConfig
108         } else {
109                 if c.Size == 0 {
110                         // Set default size if it's zero.
111                         c.Size = Size
112                 }
113                 if err := verifyConfig(c); err != nil {
114                         return nil, err
115                 }
116         }
117         d := new(digest)
118         d.initialize(c)
119         return d, nil
120 }
121
122 // initialize initializes digest with the given
123 // config, which must be non-nil and verified.
124 func (d *digest) initialize(c *Config) {
125         // Create parameter block.
126         var p [BlockSize]byte
127         p[0] = c.Size
128         p[1] = uint8(len(c.Key))
129         if c.Salt != nil {
130                 copy(p[32:], c.Salt)
131         }
132         if c.Person != nil {
133                 copy(p[48:], c.Person)
134         }
135         if c.Tree != nil {
136                 p[2] = c.Tree.Fanout
137                 p[3] = c.Tree.MaxDepth
138                 binary.LittleEndian.PutUint32(p[4:], c.Tree.LeafSize)
139                 binary.LittleEndian.PutUint64(p[8:], c.Tree.NodeOffset)
140                 p[16] = c.Tree.NodeDepth
141                 p[17] = c.Tree.InnerHashSize
142         } else {
143                 p[2] = 1
144                 p[3] = 1
145         }
146
147         // Initialize.
148         d.size = c.Size
149         for i := 0; i < 8; i++ {
150                 d.h[i] = iv[i] ^ binary.LittleEndian.Uint64(p[i*8:])
151         }
152         if c.Tree != nil && c.Tree.IsLastNode {
153                 d.isLastNode = true
154         }
155
156         // Process key.
157         if c.Key != nil {
158                 copy(d.paddedKey[:], c.Key)
159                 d.Write(d.paddedKey[:])
160                 d.isKeyed = true
161         }
162         // Save a copy of initialized state.
163         copy(d.ih[:], d.h[:])
164 }
165
166 // New512 returns a new hash.Hash computing the BLAKE2b 64-byte checksum.
167 func New512() hash.Hash {
168         d := new(digest)
169         d.initialize(defaultConfig)
170         return d
171 }
172
173 // New256 returns a new hash.Hash computing the BLAKE2b 32-byte checksum.
174 func New256() hash.Hash {
175         d := new(digest)
176         d.initialize(config256)
177         return d
178 }
179
180 // NewMAC returns a new hash.Hash computing BLAKE2b prefix-
181 // Message Authentication Code of the given size in bytes
182 // (up to 64) with the given key (up to 64 bytes in length).
183 func NewMAC(outBytes uint8, key []byte) hash.Hash {
184         d, err := New(&Config{Size: outBytes, Key: key})
185         if err != nil {
186                 panic(err.Error())
187         }
188         return d
189 }
190
191 // Reset resets the state of digest to the initial state
192 // after configuration and keying.
193 func (d *digest) Reset() {
194         copy(d.h[:], d.ih[:])
195         d.t[0] = 0
196         d.t[1] = 0
197         d.f[0] = 0
198         d.f[1] = 0
199         d.nx = 0
200         if d.isKeyed {
201                 d.Write(d.paddedKey[:])
202         }
203 }
204
205 // Size returns the digest size in bytes.
206 func (d *digest) Size() int { return int(d.size) }
207
208 // BlockSize returns the algorithm block size in bytes.
209 func (d *digest) BlockSize() int { return BlockSize }
210
211 func (d *digest) Write(p []byte) (nn int, err error) {
212         nn = len(p)
213         left := BlockSize - d.nx
214         if len(p) > left {
215                 // Process buffer.
216                 copy(d.x[d.nx:], p[:left])
217                 p = p[left:]
218                 compress(d, d.x[:])
219                 d.nx = 0
220         }
221         // Process full blocks except for the last one.
222         if len(p) > BlockSize {
223                 n := len(p) &^ (BlockSize - 1)
224                 if n == len(p) {
225                         n -= BlockSize
226                 }
227                 compress(d, p[:n])
228                 p = p[n:]
229         }
230         // Fill buffer.
231         d.nx += copy(d.x[d.nx:], p)
232         return
233 }
234
235 // Sum returns the calculated checksum.
236 func (d *digest) Sum(in []byte) []byte {
237         // Make a copy of d so that caller can keep writing and summing.
238         d0 := *d
239         hash := d0.checkSum()
240         return append(in, hash[:d0.size]...)
241 }
242
243 func (d *digest) checkSum() [Size]byte {
244         // Do not create unnecessary copies of the key.
245         if d.isKeyed {
246                 for i := 0; i < len(d.paddedKey); i++ {
247                         d.paddedKey[i] = 0
248                 }
249         }
250
251         dec := BlockSize - uint64(d.nx)
252         if d.t[0] < dec {
253                 d.t[1]--
254         }
255         d.t[0] -= dec
256
257         // Pad buffer with zeros.
258         for i := d.nx; i < len(d.x); i++ {
259                 d.x[i] = 0
260         }
261         // Set last block flag.
262         d.f[0] = 0xffffffffffffffff
263         if d.isLastNode {
264                 d.f[1] = 0xffffffffffffffff
265         }
266         // Compress last block.
267         compress(d, d.x[:])
268
269         var out [Size]byte
270         j := 0
271         for _, s := range d.h[:(d.size-1)/8+1] {
272                 out[j+0] = byte(s >> 0)
273                 out[j+1] = byte(s >> 8)
274                 out[j+2] = byte(s >> 16)
275                 out[j+3] = byte(s >> 24)
276                 out[j+4] = byte(s >> 32)
277                 out[j+5] = byte(s >> 40)
278                 out[j+6] = byte(s >> 48)
279                 out[j+7] = byte(s >> 56)
280                 j += 8
281         }
282         return out
283 }
284
285 // Sum512 returns a 64-byte BLAKE2b hash of data.
286 func Sum512(data []byte) [64]byte {
287         var d digest
288         d.initialize(defaultConfig)
289         d.Write(data)
290         return d.checkSum()
291 }
292
293 // Sum256 returns a 32-byte BLAKE2b hash of data.
294 func Sum256(data []byte) (out [32]byte) {
295         var d digest
296         d.initialize(config256)
297         d.Write(data)
298         sum := d.checkSum()
299         copy(out[:], sum[:32])
300         return
301 }