# Path: pycoind/util/pyscrypt/pbkdf2.py
# def pbkdf2(password, salt, count, key_length, prf):
#     '''Returns the result of the Password-Based Key Derivation Function 2.
#       prf - a psuedorandom function
# 
#        See http://en.wikipedia.org/wiki/PBKDF2
#     '''
# 
#     def f(block_number):
#         '''The function "f".'''
# 
#         U = prf(password, salt + struct.pack('>L', block_number))
# 
#         if count > 1:
#             U = [ c for c in U ]
#             for i in xrange(2, 1 + count):
#                 block_xor(prf(password, ''.join(U)), 0, U, 0, len(U))
#         U = ''.join(U)
# 
#         return U
# 
#     size = 0
# 
#     block_number = 0
#     blocks = [ ]
# 
#     # The iterations
#     while size < key_length:
#         block_number += 1
#         block = f(block_number)
# 
#         blocks.append(block)
#         size += len(block)
# 
#     return ''.join(blocks)[:key_length]
# 
# Path: pycoind/util/pyscrypt/util.py
# def array_overwrite(source, source_start, dest, dest_start, length):
#     '''Overwrites the dest array with the source array.'''
# 
#     for i in xrange(0, length):
#         dest[dest_start + i] = source[source_start + i]
# 
# def block_xor(source, source_start, dest, dest_start, length):
#     '''Performs xor on arrays source and dest, storing the result back in dest.'''
# 
#     for i in xrange(0, length):
#         dest[dest_start + i] = chr(ord(dest[dest_start + i]) ^ ord(source[source_start + i]))


import hashlib
import hmac
from .pbkdf2 import pbkdf2
from .util import array_overwrite, block_xor
        block_xor(V, j * (128 * r), X, 0, 128 * r)        # ROMix - 8(inner)
        blockmix_salsa8(X, 0, 128 * r, r)                 # ROMix - 9(outer)

    array_overwrite(X, 0, B, Bi, 128 * r)                 # ROMix - 10



def hash(password, salt, N, r, p, dkLen):
    """Returns the result of the scrypt password-based key derivation function.

       Constraints:
         r * p < (2 ** 30)
         dkLen <= (((2 ** 32) - 1) * 32
         N must be a power of 2 greater than 1 (eg. 2, 4, 8, 16, 32...)
         N, r, p must be positive
     """

    # Scrypt implementation. Significant thanks to https://github.com/wg/scrypt
    if N < 2 or (N & (N - 1)): raise ValueError('Scrypt N must be a power of 2 greater than 1')

    # A psuedorandom function
    prf = lambda k, m: hmac.new(key = k, msg = m, digestmod = hashlib.sha256).digest()

    B  = [ c for c in pbkdf2(password, salt, 1, p * 128 * r, prf) ]
    XY = [ chr(0) ] * (256 * r)
    V  = [ chr(0) ] * (128 * r * N)

    for i in xrange(0, p):
        smix(B, i * 128 * r, r, N, V, XY)


# Path: pycoind/util/pyscrypt/pbkdf2.py
# def pbkdf2(password, salt, count, key_length, prf):
#     '''Returns the result of the Password-Based Key Derivation Function 2.
#       prf - a psuedorandom function
# 
#        See http://en.wikipedia.org/wiki/PBKDF2
#     '''
# 
#     def f(block_number):
#         '''The function "f".'''
# 
#         U = prf(password, salt + struct.pack('>L', block_number))
# 
#         if count > 1:
#             U = [ c for c in U ]
#             for i in xrange(2, 1 + count):
#                 block_xor(prf(password, ''.join(U)), 0, U, 0, len(U))
#         U = ''.join(U)
# 
#         return U
# 
#     size = 0
# 
#     block_number = 0
#     blocks = [ ]
# 
#     # The iterations
#     while size < key_length:
#         block_number += 1
#         block = f(block_number)
# 
#         blocks.append(block)
#         size += len(block)
# 
#     return ''.join(blocks)[:key_length]
# 
# Path: pycoind/util/pyscrypt/util.py
# def array_overwrite(source, source_start, dest, dest_start, length):
#     '''Overwrites the dest array with the source array.'''
# 
#     for i in xrange(0, length):
#         dest[dest_start + i] = source[source_start + i]
# 
# def block_xor(source, source_start, dest, dest_start, length):
#     '''Performs xor on arrays source and dest, storing the result back in dest.'''
# 
#     for i in xrange(0, length):
#         dest[dest_start + i] = chr(ord(dest[dest_start + i]) ^ ord(source[source_start + i]))


# Path: pycoind/util/pyscrypt/hash.py
import hashlib
import hmac
from .pbkdf2 import pbkdf2
from .util import array_overwrite, block_xor

        block_xor(V, j * (128 * r), X, 0, 128 * r)        # ROMix - 8(inner)
        blockmix_salsa8(X, 0, 128 * r, r)                 # ROMix - 9(outer)

    array_overwrite(X, 0, B, Bi, 128 * r)                 # ROMix - 10



def hash(password, salt, N, r, p, dkLen):
    """Returns the result of the scrypt password-based key derivation function.

       Constraints:
         r * p < (2 ** 30)
         dkLen <= (((2 ** 32) - 1) * 32
         N must be a power of 2 greater than 1 (eg. 2, 4, 8, 16, 32...)
         N, r, p must be positive
     """

    # Scrypt implementation. Significant thanks to https://github.com/wg/scrypt
    if N < 2 or (N & (N - 1)): raise ValueError('Scrypt N must be a power of 2 greater than 1')

    # A psuedorandom function
    prf = lambda k, m: hmac.new(key = k, msg = m, digestmod = hashlib.sha256).digest()

    B  = [ c for c in pbkdf2(password, salt, 1, p * 128 * r, prf) ]
    XY = [ chr(0) ] * (256 * r)
    V  = [ chr(0) ] * (128 * r * N)

    for i in xrange(0, p):
        smix(B, i * 128 * r, r, N, V, XY)


    return pbkdf2(password, ''.join(B), 1, dkLen, prf)