/****************************************************************************** * Copyright © 2013-2016 The Nxt Core Developers. * * * * See the AUTHORS.txt, DEVELOPER-AGREEMENT.txt and LICENSE.txt files at * * the top-level directory of this distribution for the individual copyright * * holder information and the developer policies on copyright and licensing. * * * * Unless otherwise agreed in a custom licensing agreement, no part of the * * Nxt software, including this file, may be copied, modified, propagated, * * or distributed except according to the terms contained in the LICENSE.txt * * file. * * * * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ package nxt.crypto; import javax.crypto.Mac; import javax.crypto.ShortBufferException; import javax.crypto.spec.SecretKeySpec; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @SuppressWarnings({"PointlessBitwiseExpression", "PointlessArithmeticExpression"}) public class Scrypt { private final Mac mac; { try { mac = Mac.getInstance("HmacSHA256"); } catch (NoSuchAlgorithmException e) { throw new IllegalStateException(e); } } private final byte[] H = new byte[32]; private final byte[] B = new byte[128 + 4]; private final int[] X = new int[32]; private final int[] V = new int[32 * 1024]; public byte[] hash(final byte input[]) { int i, j, k; System.arraycopy(input, 0, B, 0, input.length); try { mac.init(new SecretKeySpec(B, 0, 40, "HmacSHA256")); } catch (InvalidKeyException e) { throw new IllegalStateException(e); } B[40] = 0; B[41] = 0; B[42] = 0; for (i = 0; i < 4; i++) { B[43] = (byte) (i + 1); mac.update(B, 0, 44); try { mac.doFinal(H, 0); } catch (ShortBufferException e) { throw new IllegalStateException(e); } for (j = 0; j < 8; j++) { X[i * 8 + j] = (H[j * 4 + 0] & 0xff) << 0 | (H[j * 4 + 1] & 0xff) << 8 | (H[j * 4 + 2] & 0xff) << 16 | (H[j * 4 + 3] & 0xff) << 24; } } for (i = 0; i < 1024; i++) { System.arraycopy(X, 0, V, i * 32, 32); xorSalsa8(0, 16); xorSalsa8(16, 0); } for (i = 0; i < 1024; i++) { k = (X[16] & 1023) * 32; for (j = 0; j < 32; j++) X[j] ^= V[k + j]; xorSalsa8(0, 16); xorSalsa8(16, 0); } for (i = 0; i < 32; i++) { B[i * 4 + 0] = (byte) (X[i] >> 0); B[i * 4 + 1] = (byte) (X[i] >> 8); B[i * 4 + 2] = (byte) (X[i] >> 16); B[i * 4 + 3] = (byte) (X[i] >> 24); } B[128 + 3] = 1; mac.update(B, 0, 128 + 4); try { mac.doFinal(H, 0); } catch (ShortBufferException e) { throw new IllegalStateException(e); } return H; } private void xorSalsa8(int di, int xi) { int x00 = (X[di + 0] ^= X[xi + 0]); int x01 = (X[di + 1] ^= X[xi + 1]); int x02 = (X[di + 2] ^= X[xi + 2]); int x03 = (X[di + 3] ^= X[xi + 3]); int x04 = (X[di + 4] ^= X[xi + 4]); int x05 = (X[di + 5] ^= X[xi + 5]); int x06 = (X[di + 6] ^= X[xi + 6]); int x07 = (X[di + 7] ^= X[xi + 7]); int x08 = (X[di + 8] ^= X[xi + 8]); int x09 = (X[di + 9] ^= X[xi + 9]); int x10 = (X[di + 10] ^= X[xi + 10]); int x11 = (X[di + 11] ^= X[xi + 11]); int x12 = (X[di + 12] ^= X[xi + 12]); int x13 = (X[di + 13] ^= X[xi + 13]); int x14 = (X[di + 14] ^= X[xi + 14]); int x15 = (X[di + 15] ^= X[xi + 15]); for (int i = 0; i < 8; i += 2) { x04 ^= Integer.rotateLeft(x00 + x12, 7); x08 ^= Integer.rotateLeft(x04 + x00, 9); x12 ^= Integer.rotateLeft(x08 + x04, 13); x00 ^= Integer.rotateLeft(x12 + x08, 18); x09 ^= Integer.rotateLeft(x05 + x01, 7); x13 ^= Integer.rotateLeft(x09 + x05, 9); x01 ^= Integer.rotateLeft(x13 + x09, 13); x05 ^= Integer.rotateLeft(x01 + x13, 18); x14 ^= Integer.rotateLeft(x10 + x06, 7); x02 ^= Integer.rotateLeft(x14 + x10, 9); x06 ^= Integer.rotateLeft(x02 + x14, 13); x10 ^= Integer.rotateLeft(x06 + x02, 18); x03 ^= Integer.rotateLeft(x15 + x11, 7); x07 ^= Integer.rotateLeft(x03 + x15, 9); x11 ^= Integer.rotateLeft(x07 + x03, 13); x15 ^= Integer.rotateLeft(x11 + x07, 18); x01 ^= Integer.rotateLeft(x00 + x03, 7); x02 ^= Integer.rotateLeft(x01 + x00, 9); x03 ^= Integer.rotateLeft(x02 + x01, 13); x00 ^= Integer.rotateLeft(x03 + x02, 18); x06 ^= Integer.rotateLeft(x05 + x04, 7); x07 ^= Integer.rotateLeft(x06 + x05, 9); x04 ^= Integer.rotateLeft(x07 + x06, 13); x05 ^= Integer.rotateLeft(x04 + x07, 18); x11 ^= Integer.rotateLeft(x10 + x09, 7); x08 ^= Integer.rotateLeft(x11 + x10, 9); x09 ^= Integer.rotateLeft(x08 + x11, 13); x10 ^= Integer.rotateLeft(x09 + x08, 18); x12 ^= Integer.rotateLeft(x15 + x14, 7); x13 ^= Integer.rotateLeft(x12 + x15, 9); x14 ^= Integer.rotateLeft(x13 + x12, 13); x15 ^= Integer.rotateLeft(x14 + x13, 18); } X[di + 0] += x00; X[di + 1] += x01; X[di + 2] += x02; X[di + 3] += x03; X[di + 4] += x04; X[di + 5] += x05; X[di + 6] += x06; X[di + 7] += x07; X[di + 8] += x08; X[di + 9] += x09; X[di + 10] += x10; X[di + 11] += x11; X[di + 12] += x12; X[di + 13] += x13; X[di + 14] += x14; X[di + 15] += x15; } }