diff --git a/Cartfile b/Cartfile index 17516637..89a16f45 100644 --- a/Cartfile +++ b/Cartfile @@ -1,4 +1,2 @@ github "mxcl/PromiseKit" ~> 6.0 github "attaswift/BigInt" ~> 3.1 -github "krzyzanowskim/CryptoSwift" -github "Boilertalk/secp256k1.swift" diff --git a/Package.resolved b/Package.resolved index f49be87c..61d96291 100644 --- a/Package.resolved +++ b/Package.resolved @@ -10,6 +10,15 @@ "version": "3.1.0" } }, + { + "package": "Cryptor", + "repositoryURL": "https://github.com/v57/BlueCryptor.git", + "state": { + "branch": null, + "revision": "62470ce23835f8920ce58e39d59548406af85dea", + "version": "1.0.23" + } + }, { "package": "CryptoSwift", "repositoryURL": "https://github.com/krzyzanowskim/CryptoSwift.git", @@ -28,15 +37,6 @@ "version": "6.5.2" } }, - { - "package": "secp256k1", - "repositoryURL": "https://github.com/Boilertalk/secp256k1.swift.git", - "state": { - "branch": null, - "revision": "823281fe9def21b384099b72a9a53ca988317b20", - "version": "0.1.4" - } - }, { "package": "SipHash", "repositoryURL": "https://github.com/attaswift/SipHash", diff --git a/Package.swift b/Package.swift index 71fefc6a..e7e29ef8 100644 --- a/Package.swift +++ b/Package.swift @@ -7,21 +7,21 @@ let package = Package( name: "web3swift", products: [ // Products define the executables and libraries produced by a package, and make them visible to other packages. - .library(name: "web3swift", targets: ["web3swift"]) + .library(name: "web3swift", targets: ["web3swift"]), ], dependencies: [ .package(url: "https://github.com/attaswift/BigInt.git", from: "3.1.0"), - .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", from: "0.12.0"), - .package(url: "https://github.com/Boilertalk/secp256k1.swift.git", from: "0.1.1"), .package(url: "https://github.com/mxcl/PromiseKit.git", from: "6.4.0"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages which this package depends on. + .target(name: "secp256k1"), + .target(name: "keccak"), + .target(name: "scrypt"), .target( name: "web3swift", - dependencies: ["BigInt", "CryptoSwift", "secp256k1", "PromiseKit"], - path: "Sources", + dependencies: ["BigInt", "secp256k1", "keccak", "scrypt", "PromiseKit"], exclude: [ "ObjectiveC", "Utils/EIP67Code.swift", diff --git a/Sources/keccak/include/keccak.h b/Sources/keccak/include/keccak.h new file mode 100755 index 00000000..0740afbe --- /dev/null +++ b/Sources/keccak/include/keccak.h @@ -0,0 +1,24 @@ +#ifndef KECCAK_FIPS202_H +#define KECCAK_FIPS202_H +#define __STDC_WANT_LIB_EXT1__ 1 +#include +#include + +#define decshake(bits) \ + int shake##bits(uint8_t*, size_t, const uint8_t*, size_t); + +#define decsha3(bits) \ + int sha3_##bits(uint8_t*, size_t, const uint8_t*, size_t); + +#define deckeccak(bits) \ + int keccak_##bits(uint8_t*, size_t, const uint8_t*, size_t); + + +decshake(128) +decshake(256) +decsha3(224) +decsha3(256) +decsha3(384) +decsha3(512) +deckeccak(256) +#endif diff --git a/Sources/keccak/keccak.c b/Sources/keccak/keccak.c new file mode 100755 index 00000000..01d14a9a --- /dev/null +++ b/Sources/keccak/keccak.c @@ -0,0 +1,175 @@ +/** libkeccak-tiny + * + * A single-file implementation of SHA-3 and SHAKE. + * + * Implementor: David Leon Gil + * License: CC0, attribution kindly requested. Blame taken too, + * but not liability. + */ +#include "keccak.h" + +#include +#include +#include +#include + +/******** The Keccak-f[1600] permutation ********/ + +/*** Constants. ***/ +static const uint8_t rho[24] = \ + { 1, 3, 6, 10, 15, 21, + 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, + 62, 18, 39, 61, 20, 44}; +static const uint8_t pi[24] = \ + {10, 7, 11, 17, 18, 3, + 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, + 20, 14, 22, 9, 6, 1}; +static const uint64_t RC[24] = \ + {1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, + 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, + 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL, + 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, + 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL, + 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL}; + +/*** Helper macros to unroll the permutation. ***/ +#define rol(x, s) (((x) << s) | ((x) >> (64 - s))) +#define REPEAT6(e) e e e e e e +#define REPEAT24(e) REPEAT6(e e e e) +#define REPEAT5(e) e e e e e +#define FOR5(v, s, e) \ + v = 0; \ + REPEAT5(e; v += s;) + +/*** Keccak-f[1600] ***/ +static inline void keccakf(void* state) { + uint64_t* a = (uint64_t*)state; + uint64_t b[5] = {0}; + uint64_t t = 0; + uint8_t x, y; + + for (int i = 0; i < 24; i++) { + // Theta + FOR5(x, 1, + b[x] = 0; + FOR5(y, 5, + b[x] ^= a[x + y]; )) + FOR5(x, 1, + FOR5(y, 5, + a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); )) + // Rho and pi + t = a[1]; + x = 0; + REPEAT24(b[0] = a[pi[x]]; + a[pi[x]] = rol(t, rho[x]); + t = b[0]; + x++; ) + // Chi + FOR5(y, + 5, + FOR5(x, 1, + b[x] = a[y + x];) + FOR5(x, 1, + a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); )) + // Iota + a[0] ^= RC[i]; + } +} + +/******** The FIPS202-defined functions. ********/ + +/*** Some helper macros. ***/ + +#define _(S) do { S } while (0) +#define FOR(i, ST, L, S) \ + _(for (size_t i = 0; i < L; i += ST) { S; }) +#define mkapply_ds(NAME, S) \ + static inline void NAME(uint8_t* dst, \ + const uint8_t* src, \ + size_t len) { \ + FOR(i, 1, len, S); \ + } +#define mkapply_sd(NAME, S) \ + static inline void NAME(const uint8_t* src, \ + uint8_t* dst, \ + size_t len) { \ + FOR(i, 1, len, S); \ + } + +mkapply_ds(xorin, dst[i] ^= src[i]) // xorin +mkapply_sd(setout, dst[i] = src[i]) // setout + +#define P keccakf +#define Plen 200 + +// Fold P*F over the full blocks of an input. +#define foldP(I, L, F) \ + while (L >= rate) { \ + F(a, I, rate); \ + P(a); \ + I += rate; \ + L -= rate; \ + } + +/** The sponge-based hash construction. **/ +static inline int hash(uint8_t* out, size_t outlen, + const uint8_t* in, size_t inlen, + size_t rate, uint8_t delim) { + if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) { + return -1; + } + uint8_t a[Plen] = {0}; + // Absorb input. + foldP(in, inlen, xorin); + // Xor in the DS and pad frame. + a[inlen] ^= delim; + a[rate - 1] ^= 0x80; + // Xor in the last block. + xorin(a, in, inlen); + // Apply P + P(a); + // Squeeze output. + foldP(out, outlen, setout); + setout(a, out, outlen); + memset_s(a, 200, 0, 200); + return 0; +} + +/*** Helper macros to define SHA3 and SHAKE instances. ***/ +#define defshake(bits) \ + int shake##bits(uint8_t* out, size_t outlen, \ + const uint8_t* in, size_t inlen) { \ + return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x1f); \ + } +#define defsha3(bits) \ + int sha3_##bits(uint8_t* out, size_t outlen, \ + const uint8_t* in, size_t inlen) { \ + if (outlen > (bits/8)) { \ + return -1; \ + } \ + return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x06); \ + } + +#define defkeccak(bits) \ + int keccak_##bits(uint8_t* out, size_t outlen, \ + const uint8_t* in, size_t inlen) { \ + if (outlen > (bits/8)) { \ + return -1; \ + } \ + return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \ +} + +/*** FIPS202 SHAKE VOFs ***/ +defshake(128) +defshake(256) + +/*** FIPS202 SHA3 FOFs ***/ +defsha3(224) +defsha3(256) +defsha3(384) +defsha3(512) + +/*** pre-FIPS202 Keccak standard ***/ +defkeccak(256) diff --git a/Sources/scrypt/asprintf.c b/Sources/scrypt/asprintf.c new file mode 100755 index 00000000..d9be9246 --- /dev/null +++ b/Sources/scrypt/asprintf.c @@ -0,0 +1,49 @@ +#include +#include +#include + +#include "asprintf.h" + +/** + * asprintf(ret, format, ...): + * Do asprintf(3) like GNU and BSD do. + */ +int +asprintf(char ** ret, const char * format, ...) +{ + va_list ap; + int len; + size_t buflen; + + /* Figure out how long the string needs to be. */ + va_start(ap, format); + len = vsnprintf(NULL, 0, format, ap); + va_end(ap); + + /* Did we fail? */ + if (len < 0) + goto err0; + buflen = (size_t)(len) + 1; + + /* Allocate memory. */ + if ((*ret = malloc(buflen)) == NULL) + goto err0; + + /* Actually generate the string. */ + va_start(ap, format); + len = vsnprintf(*ret, buflen, format, ap); + va_end(ap); + + /* Did we fail? */ + if (len < 0) + goto err1; + + /* Success! */ + return (len); + +err1: + free(*ret); +err0: + /* Failure! */ + return (-1); +} diff --git a/Sources/scrypt/asprintf.h b/Sources/scrypt/asprintf.h new file mode 100755 index 00000000..0c8352b9 --- /dev/null +++ b/Sources/scrypt/asprintf.h @@ -0,0 +1,16 @@ +#ifndef _ASPRINTF_H_ +#define _ASPRINTF_H_ + +/* Avoid namespace collisions with BSD/GNU asprintf. */ +#ifdef asprintf +#undef asprintf +#endif +#define asprintf libcperciva_asprintf + +/** + * asprintf(ret, format, ...): + * Do asprintf(3) like GNU and BSD do. + */ +int asprintf(char **, const char *, ...); + +#endif /* !_ASPRINTF_H_ */ diff --git a/Sources/scrypt/crypto_scrypt.c b/Sources/scrypt/crypto_scrypt.c new file mode 100755 index 00000000..5217814f --- /dev/null +++ b/Sources/scrypt/crypto_scrypt.c @@ -0,0 +1,243 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ + +#include +#include + +#include +#include +#include +#include + +#include "sha256.h" +#include "warnp.h" + +#include "crypto_scrypt_smix.h" +#include "crypto_scrypt_smix_sse2.h" + +#include "scrypt.h" + +static void (*smix_func)(uint8_t *, size_t, uint64_t, void *, void *) = NULL; + +/** + * _crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen, smix): + * Perform the requested scrypt computation, using ${smix} as the smix routine. + */ +static int +private_crypto_scrypt(const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t _r, uint32_t _p, + uint8_t * buf, size_t buflen, + void (*smix)(uint8_t *, size_t, uint64_t, void *, void *)) +{ + void * B0, * V0, * XY0; + uint8_t * B; + uint32_t * V; + uint32_t * XY; + size_t r = _r, p = _p; + uint32_t i; + + /* Sanity-check parameters. */ +#if SIZE_MAX > UINT32_MAX + if (buflen > (((uint64_t)(1) << 32) - 1) * 32) { + errno = EFBIG; + goto err0; + } +#endif + if ((uint64_t)(r) * (uint64_t)(p) >= (1 << 30)) { + errno = EFBIG; + goto err0; + } + if (((N & (N - 1)) != 0) || (N < 2)) { + errno = EINVAL; + goto err0; + } + if ((r > SIZE_MAX / 128 / p) || +#if SIZE_MAX / 256 <= UINT32_MAX + (r > (SIZE_MAX - 64) / 256) || +#endif + (N > SIZE_MAX / 128 / r)) { + errno = ENOMEM; + goto err0; + } + + /* Allocate memory. */ +#ifdef HAVE_POSIX_MEMALIGN + if ((errno = posix_memalign(&B0, 64, 128 * r * p)) != 0) + goto err0; + B = (uint8_t *)(B0); + if ((errno = posix_memalign(&XY0, 64, 256 * r + 64)) != 0) + goto err1; + XY = (uint32_t *)(XY0); +#if !defined(MAP_ANON) || !defined(HAVE_MMAP) + if ((errno = posix_memalign(&V0, 64, (size_t)(128 * r * N))) != 0) + goto err2; + V = (uint32_t *)(V0); +#endif +#else + if ((B0 = malloc(128 * r * p + 63)) == NULL) + goto err0; + B = (uint8_t *)(((uintptr_t)(B0) + 63) & ~ (uintptr_t)(63)); + if ((XY0 = malloc(256 * r + 64 + 63)) == NULL) + goto err1; + XY = (uint32_t *)(((uintptr_t)(XY0) + 63) & ~ (uintptr_t)(63)); +#if !defined(MAP_ANON) || !defined(HAVE_MMAP) + if ((V0 = malloc(128 * r * N + 63)) == NULL) + goto err2; + V = (uint32_t *)(((uintptr_t)(V0) + 63) & ~ (uintptr_t)(63)); +#endif +#endif +#if defined(MAP_ANON) && defined(HAVE_MMAP) + if ((V0 = mmap(NULL, (size_t)(128 * r * N), PROT_READ | PROT_WRITE, +#ifdef MAP_NOCORE + MAP_ANON | MAP_PRIVATE | MAP_NOCORE, +#else + MAP_ANON | MAP_PRIVATE, +#endif + -1, 0)) == MAP_FAILED) + goto err2; + V = (uint32_t *)(V0); +#endif + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, 1, B, p * 128 * r); + + /* 2: for i = 0 to p - 1 do */ + for (i = 0; i < p; i++) { + /* 3: B_i <-- MF(B_i, N) */ + (smix)(&B[i * 128 * r], r, N, V, XY); + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + PBKDF2_SHA256(passwd, passwdlen, B, p * 128 * r, 1, buf, buflen); + + /* Free memory. */ +#if defined(MAP_ANON) && defined(HAVE_MMAP) + if (munmap(V0, (size_t)(128 * r * N))) + goto err2; +#else + free(V0); +#endif + free(XY0); + free(B0); + + /* Success! */ + return (0); + +err2: + free(XY0); +err1: + free(B0); +err0: + /* Failure! */ + return (-1); +} + +#define TESTLEN 64 +static struct scrypt_test { + const char * passwd; + const char * salt; + uint64_t N; + uint32_t r; + uint32_t p; + uint8_t result[TESTLEN]; +} testcase = { + .passwd = "pleaseletmein", + .salt = "SodiumChloride", + .N = 16, + .r = 8, + .p = 1, + .result = { + 0x25, 0xa9, 0xfa, 0x20, 0x7f, 0x87, 0xca, 0x09, + 0xa4, 0xef, 0x8b, 0x9f, 0x77, 0x7a, 0xca, 0x16, + 0xbe, 0xb7, 0x84, 0xae, 0x18, 0x30, 0xbf, 0xbf, + 0xd3, 0x83, 0x25, 0xaa, 0xbb, 0x93, 0x77, 0xdf, + 0x1b, 0xa7, 0x84, 0xd7, 0x46, 0xea, 0x27, 0x3b, + 0xf5, 0x16, 0xa4, 0x6f, 0xbf, 0xac, 0xf5, 0x11, + 0xc5, 0xbe, 0xba, 0x4c, 0x4a, 0xb3, 0xac, 0xc7, + 0xfa, 0x6f, 0x46, 0x0b, 0x6c, 0x0f, 0x47, 0x7b, + } +}; + +static int +testsmix(void (*smix)(uint8_t *, size_t, uint64_t, void *, void *)) +{ + uint8_t hbuf[TESTLEN]; + + /* Perform the computation. */ + if (private_crypto_scrypt( + (const uint8_t *)testcase.passwd, strlen(testcase.passwd), + (const uint8_t *)testcase.salt, strlen(testcase.salt), + testcase.N, testcase.r, testcase.p, hbuf, TESTLEN, smix)) + return (-1); + + /* Does it match? */ + return (memcmp(testcase.result, hbuf, TESTLEN)); +} + +static void +selectsmix(void) +{ + + if (!testsmix(crypto_scrypt_smix_sse2)) { + smix_func = crypto_scrypt_smix_sse2; + return; + } + + /* If generic smix works, use it. */ + if (!testsmix(crypto_scrypt_smix)) { + smix_func = crypto_scrypt_smix; + return; + } + warn0("Generic scrypt code is broken - please report bug!"); + + /* If we get here, something really bad happened. */ + abort(); +} + +/** + * crypto_scrypt(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen): + * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r, + * p, buflen) and write the result into buf. The parameters r, p, and buflen + * must satisfy r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter N + * must be a power of 2 greater than 1. + * + * Return 0 on success; or -1 on error. + */ +int +crypto_scrypt(const uint8_t * passwd, size_t passwdlen, + const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t _r, uint32_t _p, + uint8_t * buf, size_t buflen) +{ + + if (smix_func == NULL) + selectsmix(); + + return (private_crypto_scrypt(passwd, passwdlen, salt, saltlen, N, _r, _p, + buf, buflen, smix_func)); +} diff --git a/Sources/scrypt/crypto_scrypt_smix.c b/Sources/scrypt/crypto_scrypt_smix.c new file mode 100755 index 00000000..bcdd8b05 --- /dev/null +++ b/Sources/scrypt/crypto_scrypt_smix.c @@ -0,0 +1,213 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#include + +#include "sysendian.h" + +#include "crypto_scrypt_smix.h" + +static void blkcpy(void *, const void *, size_t); +static void blkxor(void *, const void *, size_t); +static void salsa20_8(uint32_t[16]); +static void blockmix_salsa8(const uint32_t *, uint32_t *, uint32_t *, size_t); +static uint64_t integerify(const void *, size_t); + +static void +blkcpy(void * dest, const void * src, size_t len) +{ + size_t * D = dest; + const size_t * S = src; + size_t L = len / sizeof(size_t); + size_t i; + + for (i = 0; i < L; i++) + D[i] = S[i]; +} + +static void +blkxor(void * dest, const void * src, size_t len) +{ + size_t * D = dest; + const size_t * S = src; + size_t L = len / sizeof(size_t); + size_t i; + + for (i = 0; i < L; i++) + D[i] ^= S[i]; +} + +/** + * salsa20_8(B): + * Apply the salsa20/8 core to the provided block. + */ +static void +salsa20_8(uint32_t B[16]) +{ + uint32_t x[16]; + size_t i; + + blkcpy(x, B, 64); + for (i = 0; i < 8; i += 2) { +#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) + /* Operate on columns. */ + x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); + x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); + + x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); + x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); + + x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); + x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); + + x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); + x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); + + /* Operate on rows. */ + x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); + x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); + + x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); + x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); + + x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); + x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); + + x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); + x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); +#undef R + } + for (i = 0; i < 16; i++) + B[i] += x[i]; +} + +/** + * blockmix_salsa8(Bin, Bout, X, r): + * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r + * bytes in length; the output Bout must also be the same size. The + * temporary space X must be 64 bytes. + */ +static void +blockmix_salsa8(const uint32_t * Bin, uint32_t * Bout, uint32_t * X, size_t r) +{ + size_t i; + + /* 1: X <-- B_{2r - 1} */ + blkcpy(X, &Bin[(2 * r - 1) * 16], 64); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < 2 * r; i += 2) { + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 16], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 8], X, 64); + + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 16 + 16], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 8 + r * 16], X, 64); + } +} + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + */ +static uint64_t +integerify(const void * B, size_t r) +{ + const uint32_t * X = (const void *)((uintptr_t)(B) + (2 * r - 1) * 64); + + return (((uint64_t)(X[1]) << 32) + X[0]); +} + +/** + * crypto_scrypt_smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; + * the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a + * multiple of 64 bytes. + */ +void +crypto_scrypt_smix(uint8_t * B, size_t r, uint64_t N, void * _V, void * XY) +{ + uint32_t * X = XY; + uint32_t * Y = (void *)((uint8_t *)(XY) + 128 * r); + uint32_t * Z = (void *)((uint8_t *)(XY) + 256 * r); + uint32_t * V = _V; + uint64_t i; + uint64_t j; + size_t k; + + /* 1: X <-- B */ + for (k = 0; k < 32 * r; k++) + X[k] = le32dec(&B[4 * k]); + + /* 2: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 3: V_i <-- X */ + blkcpy(&V[i * (32 * r)], X, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(X, Y, Z, r); + + /* 3: V_i <-- X */ + blkcpy(&V[(i + 1) * (32 * r)], Y, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(Y, X, Z, r); + } + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(X, &V[j * (32 * r)], 128 * r); + blockmix_salsa8(X, Y, Z, r); + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(Y, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(Y, &V[j * (32 * r)], 128 * r); + blockmix_salsa8(Y, X, Z, r); + } + + /* 10: B' <-- X */ + for (k = 0; k < 32 * r; k++) + le32enc(&B[4 * k], X[k]); +} diff --git a/Sources/scrypt/crypto_scrypt_smix.h b/Sources/scrypt/crypto_scrypt_smix.h new file mode 100755 index 00000000..576cf989 --- /dev/null +++ b/Sources/scrypt/crypto_scrypt_smix.h @@ -0,0 +1,17 @@ +#ifndef _CRYPTO_SCRYPT_SMIX_H_ +#define _CRYPTO_SCRYPT_SMIX_H_ + +#include +#include + +/** + * crypto_scrypt_smix(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; + * the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a + * multiple of 64 bytes. + */ +void crypto_scrypt_smix(uint8_t *, size_t, uint64_t, void *, void *); + +#endif /* !_CRYPTO_SCRYPT_SMIX_H_ */ diff --git a/Sources/scrypt/crypto_scrypt_smix_sse2.c b/Sources/scrypt/crypto_scrypt_smix_sse2.c new file mode 100755 index 00000000..0678ab81 --- /dev/null +++ b/Sources/scrypt/crypto_scrypt_smix_sse2.c @@ -0,0 +1,244 @@ +/*- + * Copyright 2009 Colin Percival + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file was originally written by Colin Percival as part of the Tarsnap + * online backup system. + */ +#include +#include + +#include "sysendian.h" + +#include "crypto_scrypt_smix_sse2.h" + +static void blkcpy(void *, const void *, size_t); +static void blkxor(void *, const void *, size_t); +static void salsa20_8(__m128i *); +static void blockmix_salsa8(const __m128i *, __m128i *, __m128i *, size_t); +static uint64_t integerify(const void *, size_t); + +static void +blkcpy(void * dest, const void * src, size_t len) +{ + __m128i * D = dest; + const __m128i * S = src; + size_t L = len / 16; + size_t i; + + for (i = 0; i < L; i++) + D[i] = S[i]; +} + +static void +blkxor(void * dest, const void * src, size_t len) +{ + __m128i * D = dest; + const __m128i * S = src; + size_t L = len / 16; + size_t i; + + for (i = 0; i < L; i++) + D[i] = _mm_xor_si128(D[i], S[i]); +} + +/** + * salsa20_8(B): + * Apply the salsa20/8 core to the provided block. + */ +static void +salsa20_8(__m128i B[4]) +{ + __m128i X0, X1, X2, X3; + __m128i T; + size_t i; + + X0 = B[0]; + X1 = B[1]; + X2 = B[2]; + X3 = B[3]; + + for (i = 0; i < 8; i += 2) { + /* Operate on "columns". */ + T = _mm_add_epi32(X0, X3); + X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 7)); + X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X1, X0); + X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9)); + X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X1); + X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 13)); + X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X3, X2); + X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18)); + X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14)); + + /* Rearrange data. */ + X1 = _mm_shuffle_epi32(X1, 0x93); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x39); + + /* Operate on "rows". */ + T = _mm_add_epi32(X0, X1); + X3 = _mm_xor_si128(X3, _mm_slli_epi32(T, 7)); + X3 = _mm_xor_si128(X3, _mm_srli_epi32(T, 25)); + T = _mm_add_epi32(X3, X0); + X2 = _mm_xor_si128(X2, _mm_slli_epi32(T, 9)); + X2 = _mm_xor_si128(X2, _mm_srli_epi32(T, 23)); + T = _mm_add_epi32(X2, X3); + X1 = _mm_xor_si128(X1, _mm_slli_epi32(T, 13)); + X1 = _mm_xor_si128(X1, _mm_srli_epi32(T, 19)); + T = _mm_add_epi32(X1, X2); + X0 = _mm_xor_si128(X0, _mm_slli_epi32(T, 18)); + X0 = _mm_xor_si128(X0, _mm_srli_epi32(T, 14)); + + /* Rearrange data. */ + X1 = _mm_shuffle_epi32(X1, 0x39); + X2 = _mm_shuffle_epi32(X2, 0x4E); + X3 = _mm_shuffle_epi32(X3, 0x93); + } + + B[0] = _mm_add_epi32(B[0], X0); + B[1] = _mm_add_epi32(B[1], X1); + B[2] = _mm_add_epi32(B[2], X2); + B[3] = _mm_add_epi32(B[3], X3); +} + +/** + * blockmix_salsa8(Bin, Bout, X, r): + * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r + * bytes in length; the output Bout must also be the same size. The + * temporary space X must be 64 bytes. + */ +static void +blockmix_salsa8(const __m128i * Bin, __m128i * Bout, __m128i * X, size_t r) +{ + size_t i; + + /* 1: X <-- B_{2r - 1} */ + blkcpy(X, &Bin[8 * r - 4], 64); + + /* 2: for i = 0 to 2r - 1 do */ + for (i = 0; i < r; i++) { + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 8], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[i * 4], X, 64); + + /* 3: X <-- H(X \xor B_i) */ + blkxor(X, &Bin[i * 8 + 4], 64); + salsa20_8(X); + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + blkcpy(&Bout[(r + i) * 4], X, 64); + } +} + +/** + * integerify(B, r): + * Return the result of parsing B_{2r-1} as a little-endian integer. + * Note that B's layout is permuted compared to the generic implementation. + */ +static uint64_t +integerify(const void * B, size_t r) +{ + const uint32_t * X = (const void *)((uintptr_t)(B) + (2 * r - 1) * 64); + + return (((uint64_t)(X[13]) << 32) + X[0]); +} + +/** + * crypto_scrypt_smix_sse2(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; + * the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a + * multiple of 64 bytes. + * + * Use SSE2 instructions. + */ +void +crypto_scrypt_smix_sse2(uint8_t * B, size_t r, uint64_t N, void * V, void * XY) +{ + __m128i * X = XY; + __m128i * Y = (void *)((uintptr_t)(XY) + 128 * r); + __m128i * Z = (void *)((uintptr_t)(XY) + 256 * r); + uint32_t * X32 = (void *)X; + uint64_t i, j; + size_t k; + + /* 1: X <-- B */ + for (k = 0; k < 2 * r; k++) { + for (i = 0; i < 16; i++) { + X32[k * 16 + i] = + le32dec(&B[(k * 16 + (i * 5 % 16)) * 4]); + } + } + + /* 2: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 3: V_i <-- X */ + blkcpy((void *)((uintptr_t)(V) + i * 128 * r), X, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(X, Y, Z, r); + + /* 3: V_i <-- X */ + blkcpy((void *)((uintptr_t)(V) + (i + 1) * 128 * r), + Y, 128 * r); + + /* 4: X <-- H(X) */ + blockmix_salsa8(Y, X, Z, r); + } + + /* 6: for i = 0 to N - 1 do */ + for (i = 0; i < N; i += 2) { + /* 7: j <-- Integerify(X) mod N */ + j = integerify(X, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(X, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r); + blockmix_salsa8(X, Y, Z, r); + + /* 7: j <-- Integerify(X) mod N */ + j = integerify(Y, r) & (N - 1); + + /* 8: X <-- H(X \xor V_j) */ + blkxor(Y, (void *)((uintptr_t)(V) + j * 128 * r), 128 * r); + blockmix_salsa8(Y, X, Z, r); + } + + /* 10: B' <-- X */ + for (k = 0; k < 2 * r; k++) { + for (i = 0; i < 16; i++) { + le32enc(&B[(k * 16 + (i * 5 % 16)) * 4], + X32[k * 16 + i]); + } + } +} + diff --git a/Sources/scrypt/crypto_scrypt_smix_sse2.h b/Sources/scrypt/crypto_scrypt_smix_sse2.h new file mode 100755 index 00000000..4a403f7d --- /dev/null +++ b/Sources/scrypt/crypto_scrypt_smix_sse2.h @@ -0,0 +1,19 @@ +#ifndef _CRYPTO_SCRYPT_SMIX_SSE2_H_ +#define _CRYPTO_SCRYPT_SMIX_SSE2_H_ + +#include +#include + +/** + * crypto_scrypt_smix_sse2(B, r, N, V, XY): + * Compute B = SMix_r(B, N). The input B must be 128r bytes in length; + * the temporary storage V must be 128rN bytes in length; the temporary + * storage XY must be 256r + 64 bytes in length. The value N must be a + * power of 2 greater than 1. The arrays B, V, and XY must be aligned to a + * multiple of 64 bytes. + * + * Use SSE2 instructions. + */ +void crypto_scrypt_smix_sse2(uint8_t *, size_t, uint64_t, void *, void *); + +#endif /* !_CRYPTO_SCRYPT_SMIX_SSE2_H_ */ diff --git a/Sources/scrypt/entropy.c b/Sources/scrypt/entropy.c new file mode 100755 index 00000000..9f83f3e7 --- /dev/null +++ b/Sources/scrypt/entropy.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include + +#include "warnp.h" + +#include "entropy.h" + +/** + * XXX Portability + * XXX We obtain random bytes from the operating system by opening + * XXX /dev/urandom and reading them from that device; this works on + * XXX modern UNIX-like operating systems but not on systems like + * XXX win32 where there is no concept of /dev/urandom. + */ + +/** + * entropy_read(buf, buflen): + * Fill the given buffer with random bytes provided by the operating system. + */ +int +entropy_read(uint8_t * buf, size_t buflen) +{ + int fd; + ssize_t lenread; + + /* Sanity-check the buffer size. */ + if (buflen > SSIZE_MAX) { + warn0("Programmer error: " + "Trying to read insane amount of random data: %zu", + buflen); + goto err0; + } + + /* Open /dev/urandom. */ + if ((fd = open("/dev/urandom", O_RDONLY)) == -1) { + warnp("open(/dev/urandom)"); + goto err0; + } + + /* Read bytes until we have filled the buffer. */ + while (buflen > 0) { + if ((lenread = read(fd, buf, buflen)) == -1) { + warnp("read(/dev/urandom)"); + goto err1; + } + + /* The random device should never EOF. */ + if (lenread == 0) { + warn0("EOF on /dev/urandom?"); + goto err1; + } + + /* We've filled a portion of the buffer. */ + buf += (size_t)lenread; + buflen -= (size_t)lenread; + } + + /* Close the device. */ + while (close(fd) == -1) { + if (errno != EINTR) { + warnp("close(/dev/urandom)"); + goto err0; + } + } + + /* Success! */ + return (0); + +err1: + close(fd); +err0: + /* Failure! */ + return (-1); +} diff --git a/Sources/scrypt/entropy.h b/Sources/scrypt/entropy.h new file mode 100755 index 00000000..fa6f1cf3 --- /dev/null +++ b/Sources/scrypt/entropy.h @@ -0,0 +1,13 @@ +#ifndef _ENTROPY_H_ +#define _ENTROPY_H_ + +#include +#include + +/** + * entropy_read(buf, buflen): + * Fill the given buffer with random bytes provided by the operating system. + */ +int entropy_read(uint8_t *, size_t); + +#endif /* !_ENTROPY_H_ */ diff --git a/Sources/scrypt/getopt.c b/Sources/scrypt/getopt.c new file mode 100755 index 00000000..949036f8 --- /dev/null +++ b/Sources/scrypt/getopt.c @@ -0,0 +1,365 @@ +#include +#include +#include +#include + +#include "getopt.h" + +/* + * Standard getopt global variables. optreset starts as non-zero in order to + * trigger initialization behaviour. + */ +const char * optarg = NULL; +int optind = 1; +int opterr = 1; +int optreset = 1; + +/* + * Quasi-internal global variables -- these are used via GETOPT macros. + */ +const char * getopt_dummy = "(dummy)"; +int getopt_initialized = 0; + +/* + * Internal variables. + */ +static const char * cmdname = NULL; +static struct opt { + const char * os; + size_t olen; + int hasarg; +} * opts = NULL; +static size_t nopts; +static size_t opt_missing; +static size_t opt_default; +static size_t opt_found; +static const char * packedopts; +static char popt[3]; +static int atexit_registered = 0; + +/* Print a message. */ +#define PRINTMSG(...) do { \ + if (cmdname != NULL) \ + fprintf(stderr, "%s: ", cmdname); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ +} while (0) + +/* Print an error message and die. */ +#define DIE(...) do { \ + PRINTMSG(__VA_ARGS__); \ + abort(); \ +} while (0) + +/* Print a warning, if warnings are enabled. */ +#define WARN(...) do { \ + if (opterr == 0) \ + break; \ + if (opt_missing != opt_default) \ + break; \ + PRINTMSG(__VA_ARGS__); \ +} while (0) + +/* Free allocated options array. */ +static void +atexit_handler(void) +{ + + free(opts); + opts = NULL; +} + +/* Reset internal state. */ +static void +reset(int argc, char * const argv[]) +{ + const char * p; + + /* If we have arguments, stash argv[0] for error messages. */ + if (argc > 0) { + /* Find the basename, without leading directories. */ + for (p = cmdname = argv[0]; *p != '\0'; p++) { + if (*p == '/') + cmdname = p + 1; + } + } + + /* Discard any registered command-line options. */ + free(opts); + opts = NULL; + + /* Register atexit handler if we haven't done so already. */ + if (!atexit_registered) { + atexit(atexit_handler); + atexit_registered = 1; + } + + /* We will start scanning from the first option. */ + optind = 1; + + /* We're not in the middle of any packed options. */ + packedopts = NULL; + + /* We haven't found any option yet. */ + opt_found = (size_t)(-1); + + /* We're not initialized yet. */ + getopt_initialized = 0; + + /* Finished resetting state. */ + optreset = 0; +} + +/* Search for an option string. */ +static size_t +searchopt(const char * os) +{ + size_t i; + + /* Scan the array of options. */ + for (i = 0; i < nopts; i++) { + /* Is there an option in this slot? */ + if (opts[i].os == NULL) + continue; + + /* Does this match up to the length of the option string? */ + if (strncmp(opts[i].os, os, opts[i].olen)) + continue; + + /* Do we have