Skip to content

Instantly share code, notes, and snippets.

@cooldaemon
Created March 15, 2014 04:06
Show Gist options
  • Save cooldaemon/9561700 to your computer and use it in GitHub Desktop.
Save cooldaemon/9561700 to your computer and use it in GitHub Desktop.
Python で整数を可逆スクランブルする ref: http://qiita.com/cooldaemon/items/d168b452c976b9dedba6
import random
class InverseDoesNotExist(Exception):
pass
def generate_salt():
"""
scramble で使用する salt と inverse_salt を生成する.
:return: salt, inverse_salt
"""
salt = _gen_salt()
return salt, _modinv(salt, 0x100000000)
def _gen_salt():
salt = random.randint(3, 0xFFFFFFFF)
if salt % 2 == 0:
salt += 1
return salt
def _egcd(a, b):
if a == 0:
return (b, 0, 1)
else:
g, y, x = _egcd(b % a, a)
return (g, x - (b // a) * y, y)
def _modinv(a, m):
g, x, y = _egcd(a, m)
if g != 1:
raise InverseDoesNotExist()
else:
return x % m
def scramble(number, salt, inverse_salt):
"""
数値を相互変換する.
:param int number: 変換する整数
:param int salt: 変換のキーとなる整数
:param int inverse_salt: 変換のキーとなる整数の 2^32 を法とする逆数
:return: 変換後の整数
"""
_assert_number(number)
_assert_salt(salt, inverse_salt)
return _trim32bit(_reverse32bit(_trim32bit(number * salt)) * inverse_salt)
def _assert_number(number):
assert 1 <= number <= 0xFFFFFFFF
def _assert_salt(salt, inverse_salt):
assert _trim32bit(salt * inverse_salt) == 1
def _reverse32bit(number):
number = ((number >> 1) & 0x55555555) | ((number & 0x55555555) << 1)
number = ((number >> 2) & 0x33333333) | ((number & 0x33333333) << 2)
number = ((number >> 4) & 0x0F0F0F0F) | ((number & 0x0F0F0F0F) << 4)
number = ((number >> 8) & 0x00FF00FF) | ((number & 0x00FF00FF) << 8)
number = (number >> 16) | (number << 16)
return number
def _trim32bit(number):
return number & 0xFFFFFFFF
salt, inverse_salt = generate_salt()
def f(number):
return scramble(number, salt, inverse_salt)
for n in xrange(1, 0xFFFFFFFF):
assert f(f(n)) == n
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment