diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..66a89e2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Package binaries +yespower + +# Misc +*.txt diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c2641f3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2021 Levi Noecker +Copyright (c) 2023 Mraksoll + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..efd6dce --- /dev/null +++ b/Makefile @@ -0,0 +1,46 @@ +WORKDIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) + +APP := yespower-go + +REVISION := $(shell git rev-parse --short=8 HEAD) +TAG := $(shell git describe --tags --exact-match $(REVISION) 2>/dev/null) + +GO111MODULE ?= auto +GOFLAGS ?= -mod=vendor + +LDFLAGS := -ldflags "-s -w" + +TEST_TOOL := go +ifneq (, $(shell which richgo)) +TEST_TOOL := richgo +endif + +.PHONY: all +all: build test + +.PHONY: build +build: + $(info # #########################################################) + $(info #) + $(info # Building $(APP)) + $(info #) + $(info # #########################################################) + GOOS=linux GOARCH=amd64 go build -o yespower $(LDFLAGS) yespower.go + +.PHONY: test tests +test tests: + $(info # #########################################################) + $(info #) + $(info # Testing $(APP)) + $(info #) + $(info # #########################################################) + $(TEST_TOOL) test -v + +.PHONY: bench benchmark +bench benchmark: + $(info # #########################################################) + $(info #) + $(info # Benchmarking $(APP)) + $(info #) + $(info # #########################################################) + $(TEST_TOOL) test -bench=Yes -benchtime 4s diff --git a/README.md b/README.md new file mode 100644 index 0000000..0a558d1 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# yespower-go +Yespower crypto algorythm port from reference implementation to Go + +* not optimized * diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..b9970a2 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github/yespower-go + +go 1.20 + +require golang.org/x/crypto v0.8.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..66fe607 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= +golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= diff --git a/yespower.go b/yespower.go new file mode 100644 index 0000000..5837edc --- /dev/null +++ b/yespower.go @@ -0,0 +1,532 @@ +// package main + +package yespower + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/binary" + "encoding/hex" + "fmt" + "math/bits" + + "golang.org/x/crypto/pbkdf2" +) + +const ( + PIter = 1 + PwxSimple = 2 + PwxGather = 4 + + // Yespower versions + // TODO: Use an enum instead? + YESPOWER_0_5 = "YESPOWER_0_5" + YESPOWER_1_0 = "YESPOWER_1_0" + + // Version specific params + Salsa20Rounds_0_5 = 8 + Salsa20Rounds_1_0 = 2 + PwxRounds_0_5 = 6 + PwxRounds_1_0 = 3 + SWidth_0_5 = 8 + SWidth_1_0 = 11 + + // Derived values + PwxBytes = PwxGather * PwxSimple * 8 + PwxWords = PwxBytes / 4 + rmin = (PwxBytes + 127) / 128 + + // Runtime derived values + // NOTE: These are in the C reference, but not sure if they apply here + // + // #define Swidth_to_Sbytes1(Swidth) ((1 << Swidth) * PWXsimple * 8) + // #define Swidth_to_Smask(Swidth) (((1 << Swidth) - 1) * PWXsimple * 8) +) + +const pers_bsty_magic = "BSTY" + +type PwxformCtx struct { + Version string + Salsa20Rounds int + PwxRounds int + w int + sWidth int + sBytes int + sMask int + S []uint32 + s0, s1, s2 int +} + +func main() { + in := []byte{0x00, 0x03, 0x06, 0x09, 0x0c, 0x0f, 0x12, 0x15, + 0x18, 0x1b, 0x1e, 0x21, 0x24, 0x27, 0x2a, 0x2d, + 0x30, 0x33, 0x36, 0x39, 0x3c, 0x3f, 0x42, 0x45, + 0x48, 0x4b, 0x4e, 0x51, 0x54, 0x57, 0x5a, 0x5d, + 0x60, 0x63, 0x66, 0x69, 0x6c, 0x6f, 0x72, 0x75, + 0x78, 0x7b, 0x7e, 0x81, 0x84, 0x87, 0x8a, 0x8d, + 0x90, 0x93, 0x96, 0x99, 0x9c, 0x9f, 0xa2, 0xa5, + 0xa8, 0xab, 0xae, 0xb1, 0xb4, 0xb7, 0xba, 0xbd, + 0xc0, 0xc3, 0xc6, 0xc9, 0xcc, 0xcf, 0xd2, 0xd5, + 0xd8, 0xdb, 0xde, 0xe1, 0xe4, 0xe7, 0xea, 0xed} + fmt.Println(Yespower(in, 2048, 8, "")) + fmt.Println(Yespower(in, 4096, 16, "")) + fmt.Println(Yescrypt(in, 2048, 8, "Client Key")) + fmt.Println(Yescrypt(in, 4096, 32, "WaviBanana")) + fmt.Println(Yescrypt(in, 4096, 32, "")) +} + +func newPwxformCtx(version string) (ctx *PwxformCtx) { + + ctx = &PwxformCtx{} + + if version == YESPOWER_0_5 { + ctx.Salsa20Rounds = Salsa20Rounds_0_5 + ctx.PwxRounds = PwxRounds_0_5 + ctx.sWidth = SWidth_0_5 + ctx.sBytes = 2 * (1 << ctx.sWidth) * PwxSimple * 8 + + } else { + ctx.Salsa20Rounds = Salsa20Rounds_1_0 + ctx.PwxRounds = PwxRounds_1_0 + ctx.sWidth = SWidth_1_0 + ctx.sBytes = 3 * (1 << ctx.sWidth) * PwxSimple * 8 + } + ctx.sMask = ((1 << ctx.sWidth) - 1) * PwxSimple * 8 + ctx.S = make([]uint32, ctx.sBytes/4) + ctx.s0 = 0 + ctx.s1 = ctx.s0 + (1< 512 * 1024 || r < 8 || r > 32 || + // (N & (N - 1)) != 0 || + // (!pers && perslen)) { + // errno = EINVAL; + // goto fail; + // } + + ctx := newPwxformCtx(version) + + shaHash := sha256.Sum256(in) + + var src []byte + if version == YESPOWER_0_5 { + src = in + } else { + src = []byte(persToken) + } + + pBufSize := 128 * r + buf := pbkdf2.Key(shaHash[:], src, PIter, pBufSize, sha256.New) + + dataSize := 128 + data := make([]byte, dataSize) + BSize := len(buf) / 4 + B := make([]uint32, BSize) + for i := 0; i < BSize; i++ { + B[i] = binary.LittleEndian.Uint32(buf[i*4:]) + if i < 128 { + data[i] = buf[i] + } + } + + // V and X are temporary storage + // X must be 128*r bytes -> 128*r/4 -> 1024 elements + // V must be 128*r*N bytes -> 128*r/4 elements -> 4194304 (128 * 32 * 1024 / 4) -> 1048576 elements + vSize := 128 * r * N / 4 + V := make([]uint32, vSize) + xSize := 128 * r / 4 + X := make([]uint32, xSize) + + smix(B, r, N, V, X, ctx) + + // NOTE: B is now a little endian []uint32 slice, and need + // to conver it to []byte slice before HMAC_SHA256 + + b := make([]byte, len(B)*4) + for idx, val := range B { + binary.LittleEndian.PutUint32(b[idx*4:], val) + } + + var final string + if ctx.Version == YESPOWER_0_5 { + bufSize := 32 + buf := pbkdf2.Key(data[:32], b, PIter, bufSize, sha256.New) + + if len(persToken) > 0 { + h := hmac.New(sha256.New, buf) + h.Write([]byte(persToken)) + out := h.Sum(nil) + + shaOut := sha256.Sum256(out) + final = hex.EncodeToString(shaOut[:]) + } else { + final = hex.EncodeToString(buf) + } + + } else { + h := hmac.New(sha256.New, b[len(b)-64:]) + h.Write(data[:32]) + final = hex.EncodeToString(h.Sum(nil)) + } + + return final +} + +func smix(B []uint32, r, N int, V, X []uint32, ctx *PwxformCtx) { + nloop_all := (N + 2) / 3 + nloop_rw := nloop_all + + // Round up to even + nloop_all++ + nloop_all &= 0xfffffffe + + if ctx.Version == YESPOWER_0_5 { + // Round down to even + nloop_rw &= 0xfffffffe + } else { + // Round up to even + nloop_rw++ + nloop_rw &= 0xfffffffe + } + + // Start mixing + // - First call to smix1 creates the S blocks + // - Second call to smix1 does the actual mixing + // TODO: Might be able to set sBytes to x/128 directly? + + smix1(B, 1, ctx.sBytes/128, ctx.S, X, ctx, true) + smix1(B, r, N, V, X, ctx, false) + + smix2(B, r, N, nloop_rw, V, X, ctx) + smix2(B, r, N, nloop_all-nloop_rw, V, X, ctx) +} + +func smix1(B []uint32, r, N int, V, X []uint32, ctx *PwxformCtx, init bool) { + var start, stop int + s := 32 * r + + for k := 0; k < 2*r; k++ { + for i := 0; i < 16; i++ { + // TODO: This might be faster to re-map B first, then + // do copy() to X + X[k*16+i] = B[k*16+(i*5%16)] + } + } + + if ctx.Version != YESPOWER_0_5 { + for k := 1; k < r; k++ { + start = (k - 1) * 32 + stop = start + 32 + copy(X[k*32:], X[start:stop]) + blockmixPwxform(X[k*32:], ctx, 1) + } + } + + for i := 0; i < N; i++ { + copy(V[i*s:], X) + + if i > 1 { + start = s * wrap(integerify(X, r), i) + stop = start + s + + for j, val := range V[start:stop] { + X[j] ^= val + } + } + + // TODO: Do this without an explicit init param + if init { + blockmixSalsa(X, ctx.Salsa20Rounds) + } else { + blockmixPwxform(X, ctx, r) + } + } + + for k := 0; k < 2*r; k++ { + for i := 0; i < 16; i++ { + B[k*16+(i*5%16)] = X[k*16+i] + } + } +} + +func smix2(B []uint32, r, N, Nloop int, V, X []uint32, ctx *PwxformCtx) { + s := 32 * r + for k := 0; k < 2*r; k++ { + for i := 0; i < 16; i++ { + X[k*16+i] = B[k*16+(i*5%16)] + } + } + + for i := 0; i < Nloop; i++ { + j := integerify(X, int(r)) & (uint32(N) - 1) + + // XOR + for k, x := range V[int(j)*s : (int(j)*s)+s] { + X[k] ^= x + } + + if Nloop != 2 { + copy(V[int(j)*s:], X[:s]) + } + + blockmixPwxform(X, ctx, r) + } + + for k := 0; k < 2*r; k++ { + for i := 0; i < 16; i++ { + B[k*16+(i*5%16)] = X[k*16+i] + } + } +} + +func blockmixSalsa(B []uint32, rounds int) { + X := make([]uint32, 16) + copy(X, B[16:]) + + for i := 0; i < 2; i++ { + // XOR current block with tmp block + for j, val := range B[i*16 : i*16+16] { + X[j] ^= val + } + + // TODO: See if we can use the x/crypto salsa208 + salsaXOR(X, X, rounds) + + copy(B[i*16:], X) + } +} + +func blockmixPwxform(B []uint32, ctx *PwxformCtx, r int) { + + var start, stop int + + X := make([]uint32, PwxWords) + + r1 := 128 * r / PwxBytes + + start = (r1 - 1) * PwxWords + stop = start + PwxWords + copy(X, B[start:stop]) + + for i := 0; i < r1; i++ { + start = i * PwxWords + stop = start + PwxWords + if r1 > 1 { + for j, val := range B[start:stop] { + X[j] ^= val + } + } + + pwxform(X, ctx) + + copy(B[start:], X[:PwxWords]) + } + + i := (r1 - 1) * PwxBytes / 64 + salsaXOR(B[i*16:], B[i*16:], ctx.Salsa20Rounds) + + // TODO: This is in the reference, but doesn't seem to run ever. + // Find out whats up with that + // for i++; i < 2*r; i++ { + // // XOR + // for j, x := range B[(i-1)*16 : (i-1)*16+16] { + // X[i*16+j] ^= x + // } + + // salsaXOR(B[i*16:], B[i*16:]) + // } +} + +func pwxform(B []uint32, ctx *PwxformCtx) { + w := ctx.w + S0, S1, S2 := ctx.s0, ctx.s1, ctx.s2 + for i := 0; i < ctx.PwxRounds; i++ { + for j := 0; j < PwxGather; j++ { + xl := B[j*4] + xh := B[j*4+1] + + p0 := uint32(S0) + 2*((xl&uint32(ctx.sMask))/8) + p1 := uint32(S1) + 2*((xh&uint32(ctx.sMask))/8) + + for k := 0; k < PwxSimple; k++ { + // TODO: probably a better/faster way to do this without rotateleft + s0 := bits.RotateLeft64(uint64(ctx.S[int(p0)+(2*k)+1]), 32) + uint64(ctx.S[int(p0)+(2*k)]) + s1 := bits.RotateLeft64(uint64(ctx.S[int(p1)+(2*k)+1]), 32) + uint64(ctx.S[int(p1)+(2*k)]) + + xl = B[j*4+k*2] + xh = B[j*4+k*2+1] + + x := uint64(xl) * uint64(xh) + x += s0 + x ^= s1 + + B[j*4+k*2] = uint32(x) + B[j*4+k*2+1] = uint32(x >> 32) + } + + if ctx.Version != YESPOWER_0_5 && (i == 0 || j < (PwxGather/2)) { + if j&1 != 0 { + for k := 0; k < PwxSimple; k++ { + ctx.S[S1+w] = B[j*4+k*2] + ctx.S[S1+w+1] = B[j*4+k*2+1] + w += 2 + } + } else { + for k := 0; k < PwxSimple; k++ { + ctx.S[S0+w+(2*k)] = B[j*4+k*2] + ctx.S[S0+w+(2*k)+1] = B[j*4+k*2+1] + } + } + } + } + } + + if ctx.Version != YESPOWER_0_5 { + ctx.s0 = S2 + ctx.s1 = S0 + ctx.s2 = S1 + ctx.w = w & ((1<<(ctx.sWidth+1))*PwxSimple - 1) + } +} + +func integerify(X []uint32, r int) uint32 { + return X[(2*r-1)*16] +} + +func wrap(x uint32, i int) int { + n := i + for y := n; y != 0; y = n & (n - 1) { + n = y + } + return int(x&uint32(n-1)) + (i - n) +} + +// Taken/modified from +// https://github.com/golang/crypto/blob/master/scrypt/scrypt.go +// TODO: See if you can use the x/crypto implementation of either +// salsa20 or salsa20/8. Might need to convert from 16 byte +// to 64 byte? +func salsaXOR(in, out []uint32, rounds int) { + copy(out, in) + + x := make([]uint32, 16) + + /* SIMD unshuffle */ + for i := 0; i < 16; i++ { + x[i*5%16] = in[i] + } + + x0 := x[0] + x1 := x[1] + x2 := x[2] + x3 := x[3] + x4 := x[4] + x5 := x[5] + x6 := x[6] + x7 := x[7] + x8 := x[8] + x9 := x[9] + x10 := x[10] + x11 := x[11] + x12 := x[12] + x13 := x[13] + x14 := x[14] + x15 := x[15] + + for i := 0; i < rounds; i += 2 { + x4 ^= bits.RotateLeft32(x0+x12, 7) + x8 ^= bits.RotateLeft32(x4+x0, 9) + x12 ^= bits.RotateLeft32(x8+x4, 13) + x0 ^= bits.RotateLeft32(x12+x8, 18) + + x9 ^= bits.RotateLeft32(x5+x1, 7) + x13 ^= bits.RotateLeft32(x9+x5, 9) + x1 ^= bits.RotateLeft32(x13+x9, 13) + x5 ^= bits.RotateLeft32(x1+x13, 18) + + x14 ^= bits.RotateLeft32(x10+x6, 7) + x2 ^= bits.RotateLeft32(x14+x10, 9) + x6 ^= bits.RotateLeft32(x2+x14, 13) + x10 ^= bits.RotateLeft32(x6+x2, 18) + + x3 ^= bits.RotateLeft32(x15+x11, 7) + x7 ^= bits.RotateLeft32(x3+x15, 9) + x11 ^= bits.RotateLeft32(x7+x3, 13) + x15 ^= bits.RotateLeft32(x11+x7, 18) + + x1 ^= bits.RotateLeft32(x0+x3, 7) + x2 ^= bits.RotateLeft32(x1+x0, 9) + x3 ^= bits.RotateLeft32(x2+x1, 13) + x0 ^= bits.RotateLeft32(x3+x2, 18) + + x6 ^= bits.RotateLeft32(x5+x4, 7) + x7 ^= bits.RotateLeft32(x6+x5, 9) + x4 ^= bits.RotateLeft32(x7+x6, 13) + x5 ^= bits.RotateLeft32(x4+x7, 18) + + x11 ^= bits.RotateLeft32(x10+x9, 7) + x8 ^= bits.RotateLeft32(x11+x10, 9) + x9 ^= bits.RotateLeft32(x8+x11, 13) + x10 ^= bits.RotateLeft32(x9+x8, 18) + + x12 ^= bits.RotateLeft32(x15+x14, 7) + x13 ^= bits.RotateLeft32(x12+x15, 9) + x14 ^= bits.RotateLeft32(x13+x12, 13) + x15 ^= bits.RotateLeft32(x14+x13, 18) + } + + x[0] = x0 + x[1] = x1 + x[2] = x2 + x[3] = x3 + x[4] = x4 + x[5] = x5 + x[6] = x6 + x[7] = x7 + x[8] = x8 + x[9] = x9 + x[10] = x10 + x[11] = x11 + x[12] = x12 + x[13] = x13 + x[14] = x14 + x[15] = x15 + + //* SIMD shuffle */ + for i := 0; i < 16; i++ { + out[i] += x[i*5%16] + } +} + +func YespowerHash(input []byte) []byte { + timeBytes := input[68:72] + time := binary.LittleEndian.Uint32(timeBytes) + + var result string + if time > 1676761800 { + result = Yescrypt(input, 4096, 16, "Client Key") + } else { + result = Yespower(input, 2048, 32, "") + } + + hashBytes, _ := hex.DecodeString(result) + return hashBytes +} diff --git a/yespower_test.go b/yespower_test.go new file mode 100644 index 0000000..71caf1b --- /dev/null +++ b/yespower_test.go @@ -0,0 +1,121 @@ +package yespower + +import ( + "fmt" + "testing" +) + +func TestYespower(t *testing.T) { + // NOTE: 'in' values copied directly from C implementation tests + in := []byte{0x00, 0x03, 0x06, 0x09, 0x0c, 0x0f, 0x12, 0x15, + 0x18, 0x1b, 0x1e, 0x21, 0x24, 0x27, 0x2a, 0x2d, + 0x30, 0x33, 0x36, 0x39, 0x3c, 0x3f, 0x42, 0x45, + 0x48, 0x4b, 0x4e, 0x51, 0x54, 0x57, 0x5a, 0x5d, + 0x60, 0x63, 0x66, 0x69, 0x6c, 0x6f, 0x72, 0x75, + 0x78, 0x7b, 0x7e, 0x81, 0x84, 0x87, 0x8a, 0x8d, + 0x90, 0x93, 0x96, 0x99, 0x9c, 0x9f, 0xa2, 0xa5, + 0xa8, 0xab, 0xae, 0xb1, 0xb4, 0xb7, 0xba, 0xbd, + 0xc0, 0xc3, 0xc6, 0xc9, 0xcc, 0xcf, 0xd2, 0xd5, + 0xd8, 0xdb, 0xde, 0xe1, 0xe4, 0xe7, 0xea, 0xed} + + examples := []struct { + N, r int + persToken, want string + }{ + // NOTE: 'want' values copied directly from C implementation tests + {N: 2048, r: 8, persToken: "", want: "69e0e895b3df7aeeb837d71fe199e9d34f7ec46ecbca7a2c4308e51857ae9b46"}, + {N: 4096, r: 16, persToken: "", want: "33fb8f063824a4a020f63dca535f5ca66ab5576468c75d1ccaac7542f76495ac"}, + {N: 4096, r: 32, persToken: "", want: "771aeefda8fe79a0825bc7f2aee162ab5578574639ffc6ca3723cc18e5e3e285"}, + {N: 2048, r: 32, persToken: "", want: "d5efb813cd263e9b34540130233cbbc6a921fbff3431e5ec1a1abde2aea6ff4d"}, + {N: 1024, r: 32, persToken: "", want: "501b792db42e388f6e7d453c95d03a12a36016a5154a688390ddc609a40c6799"}, + {N: 1024, r: 32, persToken: "personality test", want: "1f0269acf565c49adc0ef9b8f26ab3808cdc38394a254fddeedcc3aacff6ad9d"}, + } + + for _, tt := range examples { + got := Yespower(in, tt.N, tt.r, tt.persToken) + if got != tt.want { + t.Errorf("got %s want %s", got, tt.want) + } + } +} + +func TestYescrypt(t *testing.T) { + // NOTE: 'in' values copied directly from C implementation tests + in := []byte{0x00, 0x03, 0x06, 0x09, 0x0c, 0x0f, 0x12, 0x15, + 0x18, 0x1b, 0x1e, 0x21, 0x24, 0x27, 0x2a, 0x2d, + 0x30, 0x33, 0x36, 0x39, 0x3c, 0x3f, 0x42, 0x45, + 0x48, 0x4b, 0x4e, 0x51, 0x54, 0x57, 0x5a, 0x5d, + 0x60, 0x63, 0x66, 0x69, 0x6c, 0x6f, 0x72, 0x75, + 0x78, 0x7b, 0x7e, 0x81, 0x84, 0x87, 0x8a, 0x8d, + 0x90, 0x93, 0x96, 0x99, 0x9c, 0x9f, 0xa2, 0xa5, + 0xa8, 0xab, 0xae, 0xb1, 0xb4, 0xb7, 0xba, 0xbd, + 0xc0, 0xc3, 0xc6, 0xc9, 0xcc, 0xcf, 0xd2, 0xd5, + 0xd8, 0xdb, 0xde, 0xe1, 0xe4, 0xe7, 0xea, 0xed} + + examples := []struct { + N, r int + persToken, want string + }{ + // NOTE: 'want' values copied directly from C implementation tests + {N: 2048, r: 8, persToken: "Client Key", want: "a59fec4c4fdda16e3b1405adda66d525b68e7cadfcfe6ac066c7ad118cd80590"}, + {N: 2048, r: 8, persToken: pers_bsty_magic, want: "5ea2b2956a9eace30a3237ff1d441edee1dc25aab8f0ea15c12165f83a7bc265"}, + {N: 4096, r: 16, persToken: "Client Key", want: "927e72d0ded3d80475473f40f1743c67289d453d5242d4f55af4e325e06699c5"}, + {N: 4096, r: 24, persToken: "Jagaricoin", want: "0e1366973211e7fea8ad9d81989c84a254d968c9d333dd8ff099324f38611e04"}, + {N: 4096, r: 32, persToken: "WaviBanana", want: "3ae05abb3c5cf6f75415a92554c98d50e38ec9552cfa78373616f480b24e559f"}, + {N: 2048, r: 32, persToken: "Client Key", want: "560a891b5ca2e1c636111a9ff7c894a5d0a2602f43fdcfa5949b95e22fe4461e"}, + {N: 1024, r: 32, persToken: "Client Key", want: "2a79e53d1be6669bc556ccc417bce3d22a74a232f56b8e1d39b45792675de108"}, + {N: 2048, r: 8, persToken: "", want: "5ecbd8e8d7c90baed4bbf8916a1225dcc3c65f5c9165bae81cdde3cffad128e8"}, + } + + for _, tt := range examples { + if tt.persToken == pers_bsty_magic { + tt.persToken = fmt.Sprintf("%s", in) + } + got := Yescrypt(in, tt.N, tt.r, tt.persToken) + if got != tt.want { + t.Errorf("got %s want %s", got, tt.want) + } + } +} + +var result string + +func bench(b *testing.B, version string, r, N int, pers string) { + in := []byte{0x00, 0x03, 0x06, 0x09, 0x0c, 0x0f, 0x12, 0x15, + 0x18, 0x1b, 0x1e, 0x21, 0x24, 0x27, 0x2a, 0x2d, + 0x30, 0x33, 0x36, 0x39, 0x3c, 0x3f, 0x42, 0x45, + 0x48, 0x4b, 0x4e, 0x51, 0x54, 0x57, 0x5a, 0x5d, + 0x60, 0x63, 0x66, 0x69, 0x6c, 0x6f, 0x72, 0x75, + 0x78, 0x7b, 0x7e, 0x81, 0x84, 0x87, 0x8a, 0x8d, + 0x90, 0x93, 0x96, 0x99, 0x9c, 0x9f, 0xa2, 0xa5, + 0xa8, 0xab, 0xae, 0xb1, 0xb4, 0xb7, 0xba, 0xbd, + 0xc0, 0xc3, 0xc6, 0xc9, 0xcc, 0xcf, 0xd2, 0xd5, + 0xd8, 0xdb, 0xde, 0xe1, 0xe4, 0xe7, 0xea, 0xed} + + var ignore string + for i := 0; i < b.N; i++ { + ignore = yespower(version, in, N, r, pers) + result = ignore + } +} + +// Benchmark the Yespower algo +func BenchmarkYespower_1024_32_wo_pers(b *testing.B) { bench(b, YESPOWER_1_0, 1024, 32, "") } +func BenchmarkYespower_1024_32_w__pers(b *testing.B) { + bench(b, YESPOWER_1_0, 1024, 32, "personality test") +} +func BenchmarkYespower_2048_08_wo_pers(b *testing.B) { bench(b, YESPOWER_1_0, 2048, 8, "") } +func BenchmarkYespower_2048_32_wo_pers(b *testing.B) { bench(b, YESPOWER_1_0, 2038, 32, "") } +func BenchmarkYespower_4096_16_wo_pers(b *testing.B) { bench(b, YESPOWER_1_0, 4096, 16, "") } +func BenchmarkYespower_4096_32_wo_pers(b *testing.B) { bench(b, YESPOWER_1_0, 4096, 32, "") } + +// Benchmark the Yescrypt algo +func BenchmarkYescrypt_1024_32_w__pers(b *testing.B) { bench(b, YESPOWER_0_5, 2048, 8, "Client Key") } +func BenchmarkYescrypt_2048_08_w__pers(b *testing.B) { + bench(b, YESPOWER_0_5, 2048, 8, pers_bsty_magic) +} +func BenchmarkYescrypt_2048_32_w__pers(b *testing.B) { bench(b, YESPOWER_0_5, 2048, 8, "Client Key") } +func BenchmarkYescrypt_4096_16_w__pers(b *testing.B) { bench(b, YESPOWER_0_5, 4096, 16, "Client Key") } +func BenchmarkYescrypt_4096_24_w__pers(b *testing.B) { bench(b, YESPOWER_0_5, 4096, 24, "Jagaricoin") } +func BenchmarkYescrypt_4096_32_w__pers(b *testing.B) { bench(b, YESPOWER_0_5, 4096, 32, "WaviBanana") } +func BenchmarkYescrypt_4096_32_wo_pers(b *testing.B) { bench(b, YESPOWER_0_5, 4096, 32, "") }