# 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

    # Salsa... Time to dance.
    for i in xrange(8, 0, -2):
        R(x, 4, 0, 12, 7);   R(x, 8, 4, 0, 9);    R(x, 12, 8, 4, 13);   R(x, 0, 12, 8, 18)
        R(x, 9, 5, 1, 7);    R(x, 13, 9, 5, 9);   R(x, 1, 13, 9, 13);   R(x, 5, 1, 13, 18)
        R(x, 14, 10, 6, 7);  R(x, 2, 14, 10, 9);  R(x, 6, 2, 14, 13);   R(x, 10, 6, 2, 18)
        R(x, 3, 15, 11, 7);  R(x, 7, 3, 15, 9);   R(x, 11, 7, 3, 13);   R(x, 15, 11, 7, 18)
        R(x, 1, 0, 3, 7);    R(x, 2, 1, 0, 9);    R(x, 3, 2, 1, 13);    R(x, 0, 3, 2, 18)
        R(x, 6, 5, 4, 7);    R(x, 7, 6, 5, 9);    R(x, 4, 7, 6, 13);    R(x, 5, 4, 7, 18)
        R(x, 11, 10, 9, 7);  R(x, 8, 11, 10, 9);  R(x, 9, 8, 11, 13);   R(x, 10, 9, 8, 18)
        R(x, 12, 15, 14, 7); R(x, 13, 12, 15, 9); R(x, 14, 13, 12, 13); R(x, 15, 14, 13, 18)

    # Coerce into nice happy 32-bit integers
    B32 = [ make_int32(x[i] + B32[i]) for i in xrange(0, 16) ]

    # Convert back to bytes
    for i in xrange(0, 16):
        B[i * 4 + 0] = chr((B32[i] >> 0) & 0xff)
        B[i * 4 + 1] = chr((B32[i] >> 8) & 0xff)
        B[i * 4 + 2] = chr((B32[i] >> 16) & 0xff)
        B[i * 4 + 3] = chr((B32[i] >> 24) & 0xff)


def blockmix_salsa8(BY, Bi, Yi, r):
    '''Blockmix; Used by SMix.'''

    start = Bi + (2 * r - 1) * 64
    X = [ BY[i] for i in xrange(start, start + 64) ]              # BlockMix - 1

    for i in xrange(0, 2 * r):                                    # BlockMix - 2

# 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


    # Salsa... Time to dance.
    for i in xrange(8, 0, -2):
        R(x, 4, 0, 12, 7);   R(x, 8, 4, 0, 9);    R(x, 12, 8, 4, 13);   R(x, 0, 12, 8, 18)
        R(x, 9, 5, 1, 7);    R(x, 13, 9, 5, 9);   R(x, 1, 13, 9, 13);   R(x, 5, 1, 13, 18)
        R(x, 14, 10, 6, 7);  R(x, 2, 14, 10, 9);  R(x, 6, 2, 14, 13);   R(x, 10, 6, 2, 18)
        R(x, 3, 15, 11, 7);  R(x, 7, 3, 15, 9);   R(x, 11, 7, 3, 13);   R(x, 15, 11, 7, 18)
        R(x, 1, 0, 3, 7);    R(x, 2, 1, 0, 9);    R(x, 3, 2, 1, 13);    R(x, 0, 3, 2, 18)
        R(x, 6, 5, 4, 7);    R(x, 7, 6, 5, 9);    R(x, 4, 7, 6, 13);    R(x, 5, 4, 7, 18)
        R(x, 11, 10, 9, 7);  R(x, 8, 11, 10, 9);  R(x, 9, 8, 11, 13);   R(x, 10, 9, 8, 18)
        R(x, 12, 15, 14, 7); R(x, 13, 12, 15, 9); R(x, 14, 13, 12, 13); R(x, 15, 14, 13, 18)

    # Coerce into nice happy 32-bit integers
    B32 = [ make_int32(x[i] + B32[i]) for i in xrange(0, 16) ]

    # Convert back to bytes
    for i in xrange(0, 16):
        B[i * 4 + 0] = chr((B32[i] >> 0) & 0xff)
        B[i * 4 + 1] = chr((B32[i] >> 8) & 0xff)
        B[i * 4 + 2] = chr((B32[i] >> 16) & 0xff)
        B[i * 4 + 3] = chr((B32[i] >> 24) & 0xff)


def blockmix_salsa8(BY, Bi, Yi, r):
    '''Blockmix; Used by SMix.'''

    start = Bi + (2 * r - 1) * 64
    X = [ BY[i] for i in xrange(start, start + 64) ]              # BlockMix - 1

    for i in xrange(0, 2 * r):                                    # BlockMix - 2

        block_xor(BY, i * 64, X, 0, 64)                           # BlockMix - 3(inner)