101 lines
3.0 KiB
Python
101 lines
3.0 KiB
Python
# /usr/bin/env python
|
|
# coding=utf-8
|
|
|
|
# Copyright 2010 Jonathan Bowman
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
# implied. See the License for the specific language governing
|
|
# permissions and limitations under the License.
|
|
|
|
"""Various helper functions for handling arrays, etc. using numpy"""
|
|
|
|
import struct
|
|
from operator import xor, add as add64, sub as sub64
|
|
import numpy as np
|
|
|
|
words = np.uint64
|
|
bytelist = np.uint8
|
|
bigint = np.uint64
|
|
|
|
# working out some differences between Python 2 and 3
|
|
try:
|
|
from itertools import imap, izip
|
|
except ImportError:
|
|
imap = map
|
|
izip = zip
|
|
try:
|
|
xrange = xrange
|
|
except:
|
|
xrange = range
|
|
|
|
SKEIN_KS_PARITY = np.uint64(0x1BD11BDAA9FC1A22)
|
|
|
|
# zeroed out byte string and list for convenience and performance
|
|
zero_bytes = struct.pack('64B', *[0] * 64)
|
|
zero_words = np.zeros(8, dtype=np.uint64)
|
|
|
|
# Build structs for conversion appropriate to this system, favoring
|
|
# native formats if possible for slight performance benefit
|
|
words_format_tpl = "%dQ"
|
|
if struct.pack('2B', 0, 1) == struct.pack('=H', 1): # big endian?
|
|
words_format_tpl = "<" + words_format_tpl # force little endian
|
|
else:
|
|
try: # is 64-bit integer native?
|
|
struct.unpack(words_format_tpl % 2, zero_bytes[:16])
|
|
except(struct.error): # Use standard instead of native
|
|
words_format_tpl = "=" + words_format_tpl
|
|
|
|
# build structs for one-, two- and eight-word sequences
|
|
words_format = dict(
|
|
(i,struct.Struct(words_format_tpl % i)) for i in (1,2,8))
|
|
|
|
def bytes2words(data, length=8):
|
|
"""Return a list of `length` 64-bit words from `data`.
|
|
|
|
`data` must consist of `length` * 8 bytes.
|
|
`length` must be 1, 2, or 8.
|
|
|
|
"""
|
|
return(np.fromstring(data, dtype=np.uint64))
|
|
|
|
def words2bytes(data, length=8):
|
|
"""Return a `length` * 8 byte string from `data`.
|
|
|
|
|
|
`data` must be a list of `length` 64-bit words
|
|
`length` must be 1, 2, or 8.
|
|
|
|
"""
|
|
try:
|
|
return(data.tostring())
|
|
except AttributeError:
|
|
return(np.uint64(data).tostring())
|
|
|
|
def RotL_64(x, N):
|
|
"""Return `x` rotated left by `N`."""
|
|
#return (x << np.uint64(N & 63)) | (x >> np.uint64((64-N) & 63))
|
|
return(np.left_shift(x, (N & 63), dtype=np.uint64) |
|
|
np.right_shift(x, ((64-N) & 63), dtype=np.uint64))
|
|
|
|
def RotR_64(x, N):
|
|
"""Return `x` rotated right by `N`."""
|
|
return(np.right_shift(x, (N & 63), dtype=np.uint64) |
|
|
np.left_shift(x, ((64-N) & 63), dtype=np.uint64))
|
|
|
|
def add64(a,b):
|
|
"""Return a 64-bit integer sum of `a` and `b`."""
|
|
return(np.add(a, b, dtype=np.uint64))
|
|
|
|
def sub64(a,b):
|
|
"""Return a 64-bit integer difference of `a` and `b`."""
|
|
return(np.subtract(a, b, dtype=np.uint64))
|
|
|