#!/usr/bin/env python3

import ctypes, ctypes.util
from ctypes import *
import typing
import time
import os

# make it so you can pass in libc through LIBC environ var

libc_path = os.environ.get('LIBC', os.environ.get('LIBC_PATH', ctypes.util.find_library('c')))

cdll.LoadLibrary(libc_path)
libc = CDLL(libc_path)


# setup the types / structs


'''
struct random_data
  {
    int32_t *fptr;                /* Front pointer.  */
    int32_t *rptr;                /* Rear pointer.  */
    int32_t *state;                /* Array of state values.  */
    int rand_type;                /* Type of random number generator.  */
    int rand_deg;                /* Degree of random number generator.  */
    int rand_sep;                /* Distance between front and rear.  */
    int32_t *end_ptr;                /* Pointer behind state table.  */
  };
'''
class random_data(Structure):
    _fields_ = [
        ('fptr', POINTER(c_int)),
        ('rptr', POINTER(c_int)),
        ('state', POINTER(c_int)),
        ('rand_type', c_int),
        ('rand_deg', c_int),
        ('rand_sep', c_int),
        ('end_ptr', POINTER(c_int))
    ]

rdata_type = c_char_p * 4
libc.initstate_r.argtypes = [c_int, rdata_type, c_int, POINTER(random_data)]
libc.random_r.argtypes = [POINTER(random_data), POINTER(c_int)]


# stdlib state


init = False
rdata = random_data()
state = None

def _reset_strfry() -> None:
    init = False
    rdata = random_data()
    state = None


def _init_random_state(ts: typing.Optional[int]=None, pid: typing.Optional[int]=None) -> rdata_type:
    global init, rdata, state

    _reset_strfry()

    ts = ts or int(time.time())
    pid = pid or libc.getpid()

    # init state
    state = rdata_type()
    rdata.state = None
    libc.initstate_r(c_int(ts ^ pid), state, sizeof(state), byref(rdata))
    init = True

    return rdata


# useful functions


'''
strfry - randomize a string
arg string: the str to create the anagram from
arg ts: an int representing the timestamp to use for randomness, if known
arg pid: an int representing the pid of the process which called strfry, if known
arg reset: whether or not to forcefully reset the random state
'''
def strfry(string: str, ts: typing.Optional[int]=None, pid: typing.Optional[int]=None, reset: typing.Optional[bool]=True) -> str:
    global init, rdata, state

    _initial_type_is_str = isinstance(string, str)
    string = list(string)

    if (not init) or reset:
        _init_random_state(ts = ts, pid = pid)

    # actual strfry mess :(((
    if string:
        for i in range(len(string) - 1):
            j = c_int()
            libc.random_r(byref(rdata), byref(j))
            j = j.value % (len(string) - i) + i

            string[i], string[j] = string[j], string[i]
    else:
        string = list()

    # allow us to strfry symbols
    if _initial_type_is_str:
        return ''.join(string)
    else:
        return string

'''
strfry - unrandomize a string :sunglasses:
arg string: the str anagram to decode
arg ts: an int representing the timestamp to use for randomness, if known
arg pid: an int representing the pid of the process which called strfry, if known
arg reset: whether or not to forcefully reset the random state
'''
def unstrfry(string: str, ts: typing.Optional[int]=None, pid: typing.Optional[int]=None, reset: typing.Optional[bool]=True) -> str:
    global init, rdata, state

    string = list(string)

    # use symbols to map strfry
    seq = strfry(list(range(len(string))), ts = ts, pid = pid, reset = reset)
    seq_out = [''] * len(seq)

    for symbol, i in zip(seq, range(len(seq))):
        seq_out[symbol] = string[i]

    return ''.join(seq_out)


# i use arch btw

#!/usr/bin/env python3

import ctypes, ctypes.util
from ctypes import *
import typing
import time
import os

# make it so you can pass in libc through LIBC environ var

libc_path = os.environ.get('LIBC', os.environ.get('LIBC_PATH', ctypes.util.find_library('c')))

cdll.LoadLibrary(libc_path)
libc = CDLL(libc_path)


# setup the types / structs


'''
struct random_data
  {
    int32_t *fptr;                /* Front pointer.  */
    int32_t *rptr;                /* Rear pointer.  */
    int32_t *state;                /* Array of state values.  */
    int rand_type;                /* Type of random number generator.  */
    int rand_deg;                /* Degree of random number generator.  */
    int rand_sep;                /* Distance between front and rear.  */
    int32_t *end_ptr;                /* Pointer behind state table.  */
  };
'''
class random_data(Structure):
    _fields_ = [
        ('fptr', POINTER(c_int)),
        ('rptr', POINTER(c_int)),
        ('state', POINTER(c_int)),
        ('rand_type', c_int),
        ('rand_deg', c_int),
        ('rand_sep', c_int),
        ('end_ptr', POINTER(c_int))
    ]

rdata_type = c_char_p * 4
libc.initstate_r.argtypes = [c_int, rdata_type, c_int, POINTER(random_data)]
libc.random_r.argtypes = [POINTER(random_data), POINTER(c_int)]


# stdlib state


init = False
rdata = random_data()
state = None

def _reset_strfry() -> None:
    init = False
    rdata = random_data()
    state = None


def _init_random_state(ts: typing.Optional[int]=None, pid: typing.Optional[int]=None) -> rdata_type:
    global init, rdata, state

    _reset_strfry()

    ts = ts or int(time.time())
    pid = pid or libc.getpid()

    # init state
    state = rdata_type()
    rdata.state = None
    libc.initstate_r(c_int(ts ^ pid), state, sizeof(state), byref(rdata))
    init = True

    return rdata


# useful functions


'''
strfry - randomize a string
arg string: the str to create the anagram from
arg ts: an int representing the timestamp to use for randomness, if known
arg pid: an int representing the pid of the process which called strfry, if known
arg reset: whether or not to forcefully reset the random state
'''
def strfry(string: str, ts: typing.Optional[int]=None, pid: typing.Optional[int]=None, reset: typing.Optional[bool]=True) -> str:
    global init, rdata, state

    _initial_type_is_str = isinstance(string, str)
    string = list(string)

    if (not init) or reset:
        _init_random_state(ts = ts, pid = pid)

    # actual strfry mess :(((
    if string:
        for i in range(len(string) - 1):
            j = c_int()
            libc.random_r(byref(rdata), byref(j))
            j = j.value % (len(string) - i) + i

            string[i], string[j] = string[j], string[i]
    else:
        string = list()

    # allow us to strfry symbols
    if _initial_type_is_str:
        return ''.join(string)
    else:
        return string

'''
strfry - unrandomize a string :sunglasses:
arg string: the str anagram to decode
arg ts: an int representing the timestamp to use for randomness, if known
arg pid: an int representing the pid of the process which called strfry, if known
arg reset: whether or not to forcefully reset the random state
'''
def unstrfry(string: str, ts: typing.Optional[int]=None, pid: typing.Optional[int]=None, reset: typing.Optional[bool]=True) -> str:
    global init, rdata, state

    string = list(string)

    # use symbols to map strfry
    seq = strfry(list(range(len(string))), ts = ts, pid = pid, reset = reset)
    seq_out = [''] * len(seq)

    for symbol, i in zip(seq, range(len(seq))):
        seq_out[symbol] = string[i]

    return ''.join(seq_out)


# i use arch btw

#!/usr/bin/env python3 # make it so you can pass in libc through LIBC environ var # setup the types / structs struct random_data   {     int32_t *fptr;                /* Front pointer.  */     int32_t *rptr;                /* Rear pointer.  */     int32_t *state;                /* Array of state values.  */     int rand_type;                /* Type of random number generator.  */     int rand_deg;                /* Degree of random number generator.  */     int rand_sep;                /* Distance between front and rear.  */     int32_t *end_ptr;                /* Pointer behind state table.  */   }; # stdlib state # init state # useful functions strfry - randomize a string arg string: the str to create the anagram from arg ts: an int representing the timestamp to use for randomness, if known arg pid: an int representing the pid of the process which called strfry, if known arg reset: whether or not to forcefully reset the random state # actual strfry mess :((( # allow us to strfry symbols strfry - unrandomize a string :sunglasses: arg string: the str anagram to decode arg ts: an int representing the timestamp to use for randomness, if known arg pid: an int representing the pid of the process which called strfry, if known arg reset: whether or not to forcefully reset the random state # use symbols to map strfry # i use arch btw