+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "sha2.h"
+#include "scrypt.h"
+
+/**
+ * Name RFC Description
+ * pass P Passphrase, an octet string.
+ * salt S Salt, an octet string.
+ * cost N CPU/Memory cost parameter
+ * bs r Block size parameter.
+ * par p Parallelization parameter
+ * len? dkLen Intended output length
+ * in B Input data
+ * out B' Output data
+ */
+
+/* Types */
+typedef void hash_t(uint8_t *out, const uint8_t *in, int len);
+
+/* Helpers */
+#if 0
+static int mod(uint8_t out[64], uint8_t in[64])
+{
+}
+
+static void copy(uint8_t out[64], uint8_t in[64])
+{
+}
+
+static void xor(uint8_t out[64], uint8_t a[64], uint8_t b[64])
+{
+}
+#endif
+
+/* HMAC */
+static void hmac_gen(hash_t hash,
+ uint8_t *out, int nout,
+ const uint8_t *key, int nkey,
+ const uint8_t *msg, int nmsg)
+{
+ uint8_t *fix = alloc0(nout);
+ uint8_t *ipad = alloc0(nout+nmsg);
+ uint8_t *opad = alloc0(nout+nout);
+
+ /* Fixup key */
+ if (nkey > nout)
+ hash(fix, key, nkey);
+ else
+ memcpy(fix, key, nkey);
+
+ /* Create pad strings */
+ for (int i = 0; i < nout; i++) {
+ opad[i] = 0x5c ^ fix[i];
+ ipad[i] = 0x36 ^ fix[i];
+ }
+
+ /* Run hashes - hash(o+hash(i+msg)) */
+ memcpy(ipad+nout, msg, nmsg);
+ hash(opad+nout, ipad, nout+nmsg);
+ hash(out, opad, nout+nout);
+
+ /* Cleanup */
+ free(fix);
+ free(opad);
+ free(ipad);
+}
+
+/* PBKDF2 */
+static void pbkdf2_gen(uint8_t *out, int nout,
+ const uint8_t *pass, int npass,
+ const uint8_t *salt, int nsalt,
+ int iter)
+{
+ int nbuf = nsalt + 4;
+ uint8_t *buf = alloc0(nbuf);
+ memcpy(buf, salt, nsalt);
+
+ const int nptr = 256/8;
+
+ for (int i = 0; i < nout/nptr; i++) {
+ uint8_t *ptr = &out[i*nptr];
+
+ buf[nsalt+0] = ((i+1) & 0xFF000000) >> 030;
+ buf[nsalt+1] = ((i+1) & 0x00FF0000) >> 020;
+ buf[nsalt+2] = ((i+1) & 0x0000FF00) >> 010;
+ buf[nsalt+3] = ((i+1) & 0x000000FF) >> 000;
+
+ hmac_gen(sha256_hash, ptr, nptr, pass, npass, buf, nbuf);
+ for (int j = 1; j < iter; j++)
+ hmac_gen(sha256_hash, ptr, nptr, pass, npass, ptr, nptr);
+ }
+
+ free(buf);
+}
+
+static void pbkdf2_gen_str(uint8_t *out, int nout,
+ const char *pass, const char *salt, int iter)
+{
+ pbkdf2_gen(out, nout,
+ (const uint8_t *)pass, strlen(pass),
+ (const uint8_t *)salt, strlen(salt), iter);
+}
+
+/* Salsa20/8 */
+static void salsa(uint8_t out[64], uint8_t in[64])
+{
+}
+
+/* scrypt */
+#if 0
+static void block_mix(uint8_t *out[64], uint8_t *in[64], int bs)
+{
+ // xor each block with the last block
+ // alternat first/second half for result
+
+ uint8_t tmp[64]
+ for (int i = 0; i < 2*r; i++) {
+ int o = bs*(i%2) + (i/2);
+ xor(tmp, in[2*r - 1], in[i]);
+ salsa(out[o], tmp);
+ }
+}
+
+static void ro_mix(uint8_t *out[128], uint8_t *in[128], int cost, int bs)
+{
+ // generate vector of size cost
+ // randomly collapse vector as output
+
+ uint8_t *state[64];
+ uint8_t *mixed[64];
+ uint8_t *tmp[64];
+
+ copy(state, in);
+
+ for (i = 0; i < cost; i++) {
+ copy(mixed[i], state);
+ block_mix(state, state);
+ }
+
+ for (i = 0; i < cost; i++) {
+ int j = mod(state, cost);
+ xor(tmp, state, mixed[j]);
+ block_mix(state, tmp);
+ }
+
+ copy(out, state);
+}
+
+static void scrypt_run(uint8_t out[64],
+ char *pass, char *salt,
+ int cost, int bs, int par, int len)
+{
+ // hash pass/salt into large buffer
+ // mix each buffer (in parallel)
+ // combine bubers into output
+
+ sha256_hmac(buf, pass, salt, 1, par * 128 * bs);
+
+ for (i = 0; i < par; i++)
+ buf[i] = ro_mix(buf[i], cost, bs);
+
+ sha256_hmac(out, pass, buf, 1, len);
+}
+#endif
+
+/* Entry point */
+void scrypt_hash(uint8_t *in, uint8_t *sum)
+{
+ *sum = 0;
+}
+
+/* Tests */
+#if 0
+static void test_script(void)
+{
+ /* Parameters */
+ const int cost = 1024;
+ const int bs = 1;
+ const int par = 1;
+ const int len = 32;
+
+ /* Input data */
+ const char *pass = "hello";
+ const char *salt = "world";
+
+ /* Output data */
+ static uint8_t out[32];
+
+ /* Run the hash */
+ scrypt_hash(out, pass, salt, par, bs, len);
+
+ /* Print output */
+}
+#endif
+
+static void test_keygen(void)
+{
+ const uint8_t truth0[] = {
+ 0x55, 0xac, 0x04, 0x6e, 0x56, 0xe3, 0x08, 0x9f,
+ 0xec, 0x16, 0x91, 0xc2, 0x25, 0x44, 0xb6, 0x05,
+ 0xf9, 0x41, 0x85, 0x21, 0x6d, 0xde, 0x04, 0x65,
+ 0xe6, 0x8b, 0x9d, 0x57, 0xc2, 0x0d, 0xac, 0xbc,
+ 0x49, 0xca, 0x9c, 0xcc, 0xf1, 0x79, 0xb6, 0x45,
+ 0x99, 0x16, 0x64, 0xb3, 0x9d, 0x77, 0xef, 0x31,
+ 0x7c, 0x71, 0xb8, 0x45, 0xb1, 0xe3, 0x0b, 0xd5,
+ 0x09, 0x11, 0x20, 0x41, 0xd3, 0xa1, 0x97, 0x83,
+ };
+
+ const uint8_t truth1[] = {
+ 0x4d, 0xdc, 0xd8, 0xf6, 0x0b, 0x98, 0xbe, 0x21,
+ 0x83, 0x0c, 0xee, 0x5e, 0xf2, 0x27, 0x01, 0xf9,
+ 0x64, 0x1a, 0x44, 0x18, 0xd0, 0x4c, 0x04, 0x14,
+ 0xae, 0xff, 0x08, 0x87, 0x6b, 0x34, 0xab, 0x56,
+ 0xa1, 0xd4, 0x25, 0xa1, 0x22, 0x58, 0x33, 0x54,
+ 0x9a, 0xdb, 0x84, 0x1b, 0x51, 0xc9, 0xb3, 0x17,
+ 0x6a, 0x27, 0x2b, 0xde, 0xbb, 0xa1, 0xd0, 0x78,
+ 0x47, 0x8f, 0x62, 0xb3, 0x97, 0xf3, 0x3c, 0x8d,
+ };
+
+ uint8_t out0[64] = {};
+ uint8_t out1[64] = {};
+
+ // output password salt iters
+ pbkdf2_gen_str(out0, 64, "passwd", "salt", 1);
+ //pbkdf2_gen_str(out1, 64, "Password", "NaCl", 80000);
+
+ hexdump("\nTest #1", NULL, truth0, 64);
+ hexdump("", NULL, out0, 64);
+
+ hexdump("\nTest #2", NULL, truth1, 64);
+ hexdump("", NULL, out1, 64);
+
+ (void)salsa;
+ (void)pbkdf2_gen;
+ (void)hmac_gen;
+}
+
+void scrypt_test(void)
+{
+ test_keygen();
+}