Skip to content

Commit c4d8efe

Browse files
committed
Make 2x faster.
Now uses uint32s instead of bytes for internal calculation. benchmark old ns/op new ns/op delta BenchmarkKey 266430525 126657130 -52.46% Also updated other code to go.crypto version.
1 parent 7564037 commit c4d8efe

File tree

6 files changed

+165
-140
lines changed

6 files changed

+165
-140
lines changed

AUTHORS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# This source code refers to The Go Authors for copyright purposes.
2+
# The master list of authors is in the main Go distribution,
3+
# visible at http://tip.golang.org/AUTHORS.

CONTRIBUTORS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# This source code was written by the Go contributors.
2+
# The master list of contributors is in the main Go distribution,
3+
# visible at http://tip.golang.org/CONTRIBUTORS.

LICENSE

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
1-
Copyright 2012 Dmitry Chestnykh (Go implementation)
2-
Copyright 2009 Colin Percival (original C implementation)
3-
All rights reserved.
1+
Copyright (c) 2009-2013 The Go Authors. All rights reserved.
42

53
Redistribution and use in source and binary forms, with or without
6-
modification, are permitted provided that the following conditions
7-
are met:
8-
1. Redistributions of source code must retain the above copyright
9-
notice, this list of conditions and the following disclaimer.
10-
2. Redistributions in binary form must reproduce the above copyright
11-
notice, this list of conditions and the following disclaimer in the
12-
documentation and/or other materials provided with the distribution.
4+
modification, are permitted provided that the following conditions are
5+
met:
136

14-
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15-
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16-
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17-
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18-
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19-
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20-
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21-
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22-
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23-
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24-
SUCH DAMAGE.
7+
* Redistributions of source code must retain the above copyright
8+
notice, this list of conditions and the following disclaimer.
9+
* Redistributions in binary form must reproduce the above
10+
copyright notice, this list of conditions and the following disclaimer
11+
in the documentation and/or other materials provided with the
12+
distribution.
13+
* Neither the name of Google Inc. nor the names of its
14+
contributors may be used to endorse or promote products derived from
15+
this software without specific prior written permission.
16+
17+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

README

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,4 @@ func Key(password, salt []byte, N, r, p, keyLen int) ([]byte, error)
4848
KEYWORDS
4949

5050
go, golang, scrypt, kdf
51+

scrypt.go

Lines changed: 85 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,52 @@
1-
// Copyright 2012 Dmitry Chestnykh (Go implementation)
2-
// Copyright 2009 Colin Percival (original C implementation)
3-
// All rights reserved.
1+
// Copyright 2012 The Go Authors. All rights reserved.
42
// Use of this source code is governed by a BSD-style
53
// license that can be found in the LICENSE file.
64

75
// Package scrypt implements the scrypt key derivation function as defined in
86
// Colin Percival's paper "Stronger Key Derivation via Sequential Memory-Hard
9-
// Functions".
7+
// Functions" (http://www.tarsnap.com/scrypt/scrypt.pdf).
108
package scrypt
119

1210
import (
1311
"crypto/sha256"
14-
"encoding/binary"
1512
"errors"
1613

1714
"code.google.com/p/go.crypto/pbkdf2"
1815
)
1916

20-
const maxInt = 1<<31 - 1
17+
const maxInt = int(^uint(0) >> 1)
2118

22-
// blockCopy copies n bytes from src into dst.
23-
func blockCopy(dst, src []byte, n int) {
19+
// blockCopy copies n numbers from src into dst.
20+
func blockCopy(dst, src []uint32, n int) {
2421
copy(dst, src[:n])
2522
}
2623

27-
// blockXOR XORs bytes from dst with n bytes from src.
28-
func blockXOR(dst, src []byte, n int) {
24+
// blockXOR XORs numbers from dst with n numbers from src.
25+
func blockXOR(dst, src []uint32, n int) {
2926
for i, v := range src[:n] {
3027
dst[i] ^= v
3128
}
3229
}
3330

34-
// salsa applies Salsa20/8 to the given array.
35-
func salsa(b *[64]byte) {
36-
w0 := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
37-
w1 := uint32(b[4]) | uint32(b[5])<<8 | uint32(b[6])<<16 | uint32(b[7])<<24
38-
w2 := uint32(b[8]) | uint32(b[9])<<8 | uint32(b[10])<<16 | uint32(b[11])<<24
39-
w3 := uint32(b[12]) | uint32(b[13])<<8 | uint32(b[14])<<16 | uint32(b[15])<<24
40-
w4 := uint32(b[16]) | uint32(b[17])<<8 | uint32(b[18])<<16 | uint32(b[19])<<24
41-
w5 := uint32(b[20]) | uint32(b[21])<<8 | uint32(b[22])<<16 | uint32(b[23])<<24
42-
w6 := uint32(b[24]) | uint32(b[25])<<8 | uint32(b[26])<<16 | uint32(b[27])<<24
43-
w7 := uint32(b[28]) | uint32(b[29])<<8 | uint32(b[30])<<16 | uint32(b[31])<<24
44-
w8 := uint32(b[32]) | uint32(b[33])<<8 | uint32(b[34])<<16 | uint32(b[35])<<24
45-
w9 := uint32(b[36]) | uint32(b[37])<<8 | uint32(b[38])<<16 | uint32(b[39])<<24
46-
w10 := uint32(b[40]) | uint32(b[41])<<8 | uint32(b[42])<<16 | uint32(b[43])<<24
47-
w11 := uint32(b[44]) | uint32(b[45])<<8 | uint32(b[46])<<16 | uint32(b[47])<<24
48-
w12 := uint32(b[48]) | uint32(b[49])<<8 | uint32(b[50])<<16 | uint32(b[51])<<24
49-
w13 := uint32(b[52]) | uint32(b[53])<<8 | uint32(b[54])<<16 | uint32(b[55])<<24
50-
w14 := uint32(b[56]) | uint32(b[57])<<8 | uint32(b[58])<<16 | uint32(b[59])<<24
51-
w15 := uint32(b[60]) | uint32(b[61])<<8 | uint32(b[62])<<16 | uint32(b[63])<<24
31+
// salsaXOR applies Salsa20/8 to the XOR of 16 numbers from tmp and in,
32+
// and puts the result into both both tmp and out.
33+
func salsaXOR(tmp *[16]uint32, in, out []uint32) {
34+
w0 := tmp[0] ^ in[0]
35+
w1 := tmp[1] ^ in[1]
36+
w2 := tmp[2] ^ in[2]
37+
w3 := tmp[3] ^ in[3]
38+
w4 := tmp[4] ^ in[4]
39+
w5 := tmp[5] ^ in[5]
40+
w6 := tmp[6] ^ in[6]
41+
w7 := tmp[7] ^ in[7]
42+
w8 := tmp[8] ^ in[8]
43+
w9 := tmp[9] ^ in[9]
44+
w10 := tmp[10] ^ in[10]
45+
w11 := tmp[11] ^ in[11]
46+
w12 := tmp[12] ^ in[12]
47+
w13 := tmp[13] ^ in[13]
48+
w14 := tmp[14] ^ in[14]
49+
w15 := tmp[15] ^ in[15]
5250

5351
x0, x1, x2, x3, x4, x5, x6, x7, x8 := w0, w1, w2, w3, w4, w5, w6, w7, w8
5452
x9, x10, x11, x12, x13, x14, x15 := w9, w10, w11, w12, w13, w14, w15
@@ -143,74 +141,77 @@ func salsa(b *[64]byte) {
143141
x14 += w14
144142
x15 += w15
145143

146-
b[0], b[1], b[2], b[3] = byte(x0), byte(x0>>8), byte(x0>>16), byte(x0>>24)
147-
b[4], b[5], b[6], b[7] = byte(x1), byte(x1>>8), byte(x1>>16), byte(x1>>24)
148-
b[8], b[9], b[10], b[11] = byte(x2), byte(x2>>8), byte(x2>>16), byte(x2>>24)
149-
b[12], b[13], b[14], b[15] = byte(x3), byte(x3>>8), byte(x3>>16), byte(x3>>24)
150-
b[16], b[17], b[18], b[19] = byte(x4), byte(x4>>8), byte(x4>>16), byte(x4>>24)
151-
b[20], b[21], b[22], b[23] = byte(x5), byte(x5>>8), byte(x5>>16), byte(x5>>24)
152-
b[24], b[25], b[26], b[27] = byte(x6), byte(x6>>8), byte(x6>>16), byte(x6>>24)
153-
b[28], b[29], b[30], b[31] = byte(x7), byte(x7>>8), byte(x7>>16), byte(x7>>24)
154-
b[32], b[33], b[34], b[35] = byte(x8), byte(x8>>8), byte(x8>>16), byte(x8>>24)
155-
b[36], b[37], b[38], b[39] = byte(x9), byte(x9>>8), byte(x9>>16), byte(x9>>24)
156-
b[40], b[41], b[42], b[43] = byte(x10), byte(x10>>8), byte(x10>>16), byte(x10>>24)
157-
b[44], b[45], b[46], b[47] = byte(x11), byte(x11>>8), byte(x11>>16), byte(x11>>24)
158-
b[48], b[49], b[50], b[51] = byte(x12), byte(x12>>8), byte(x12>>16), byte(x12>>24)
159-
b[52], b[53], b[54], b[55] = byte(x13), byte(x13>>8), byte(x13>>16), byte(x13>>24)
160-
b[56], b[57], b[58], b[59] = byte(x14), byte(x14>>8), byte(x14>>16), byte(x14>>24)
161-
b[60], b[61], b[62], b[63] = byte(x15), byte(x15>>8), byte(x15>>16), byte(x15>>24)
144+
out[0], tmp[0] = x0, x0
145+
out[1], tmp[1] = x1, x1
146+
out[2], tmp[2] = x2, x2
147+
out[3], tmp[3] = x3, x3
148+
out[4], tmp[4] = x4, x4
149+
out[5], tmp[5] = x5, x5
150+
out[6], tmp[6] = x6, x6
151+
out[7], tmp[7] = x7, x7
152+
out[8], tmp[8] = x8, x8
153+
out[9], tmp[9] = x9, x9
154+
out[10], tmp[10] = x10, x10
155+
out[11], tmp[11] = x11, x11
156+
out[12], tmp[12] = x12, x12
157+
out[13], tmp[13] = x13, x13
158+
out[14], tmp[14] = x14, x14
159+
out[15], tmp[15] = x15, x15
162160
}
163161

164-
func blockMix(b, y []byte, r int) {
165-
var x [64]byte
166-
xs := x[:]
167-
168-
blockCopy(xs, b[(2*r-1)*64:], 64)
169-
170-
for i := 0; i < 2*r; i++ {
171-
blockXOR(xs, b[i*64:], 64)
172-
salsa(&x)
173-
174-
blockCopy(y[i*64:], xs, 64)
175-
}
176-
177-
for i := 0; i < r; i++ {
178-
blockCopy(b[i*64:], y[(i*2)*64:], 64)
179-
}
180-
181-
for i := 0; i < r; i++ {
182-
blockCopy(b[(i+r)*64:], y[(i*2+1)*64:], 64)
162+
func blockMix(tmp *[16]uint32, in, out []uint32, r int) {
163+
blockCopy(tmp[:], in[(2*r-1)*16:], 16)
164+
for i := 0; i < 2*r; i += 2 {
165+
salsaXOR(tmp, in[i*16:], out[i*8:])
166+
salsaXOR(tmp, in[i*16+16:], out[i*8+r*16:])
183167
}
184168
}
185169

186-
func integerify(b []byte, r int) uint64 {
187-
return binary.LittleEndian.Uint64(b[(2*r-1)*64:])
170+
func integer(b []uint32, r int) uint64 {
171+
j := (2*r - 1) * 16
172+
return uint64(b[j]) | uint64(b[j+1])<<32
188173
}
189174

190-
func smix(b []byte, r, N int, v, xy []byte) {
175+
func smix(b []byte, r, N int, v, xy []uint32) {
176+
var tmp [16]uint32
191177
x := xy
192-
y := xy[128*r:]
193-
194-
blockCopy(x, b, 128*r)
178+
y := xy[32*r:]
195179

196-
for i := 0; i < N; i++ {
197-
blockCopy(v[i*(128*r):], x, 128*r)
198-
blockMix(x, y, r)
180+
j := 0
181+
for i := 0; i < 32*r; i++ {
182+
x[i] = uint32(b[j]) | uint32(b[j+1])<<8 | uint32(b[j+2])<<16 | uint32(b[j+3])<<24
183+
j += 4
199184
}
185+
for i := 0; i < N; i += 2 {
186+
blockCopy(v[i*(32*r):], x, 32*r)
187+
blockMix(&tmp, x, y, r)
200188

201-
for i := 0; i < N; i++ {
202-
j := int(integerify(x, r) & uint64(N-1))
203-
blockXOR(x, v[j*(128*r):], 128*r)
204-
blockMix(x, y, r)
189+
blockCopy(v[(i+1)*(32*r):], y, 32*r)
190+
blockMix(&tmp, y, x, r)
191+
}
192+
for i := 0; i < N; i += 2 {
193+
j := int(integer(x, r) & uint64(N-1))
194+
blockXOR(x, v[j*(32*r):], 32*r)
195+
blockMix(&tmp, x, y, r)
196+
197+
j = int(integer(y, r) & uint64(N-1))
198+
blockXOR(y, v[j*(32*r):], 32*r)
199+
blockMix(&tmp, y, x, r)
200+
}
201+
j = 0
202+
for _, v := range x[:32*r] {
203+
b[j+0] = byte(v >> 0)
204+
b[j+1] = byte(v >> 8)
205+
b[j+2] = byte(v >> 16)
206+
b[j+3] = byte(v >> 24)
207+
j += 4
205208
}
206-
207-
blockCopy(b, x, 128*r)
208209
}
209210

210-
// Key derives a key from the password, salt and cost parameters, returning a
211-
// byte slice of length keyLen that can be used as cryptographic key.
212-
//
213-
// N is a CPU/memory cost parameter, must be a power of two greater than 1.
211+
// Key derives a key from the password, salt, and cost parameters, returning
212+
// a byte slice of length keyLen that can be used as cryptographic key.
213+
//
214+
// N is a CPU/memory cost parameter, which must be a power of two greater than 1.
214215
// r and p must satisfy r * p < 2³⁰. If the parameters do not satisfy the
215216
// limits, the function returns a nil byte slice and an error.
216217
//
@@ -230,8 +231,8 @@ func Key(password, salt []byte, N, r, p, keyLen int) ([]byte, error) {
230231
return nil, errors.New("scrypt: parameters are too large")
231232
}
232233

233-
xy := make([]byte, 256*r)
234-
v := make([]byte, 128*r*N)
234+
xy := make([]uint32, 64*r)
235+
v := make([]uint32, 32*N*r)
235236
b := pbkdf2.Key(password, salt, 1, p*128*r, sha256.New)
236237

237238
for i := 0; i < p; i++ {

0 commit comments

Comments
 (0)