Skip to content

Instantly share code, notes, and snippets.

@yiunsr
Last active September 25, 2022 12:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yiunsr/d1186be93fb99119a15a0917efdb1d27 to your computer and use it in GitHub Desktop.
Save yiunsr/d1186be93fb99119a15a0917efdb1d27 to your computer and use it in GitHub Desktop.

Non deuplicate random generator

  • Simple encryption through one-to-one correspondence operation
  • It is an unsafe random function, so do not use it if security is required.
  • For operation, the key size should be 4 to 8 bytes.

중복되지 않는 랜덤 number 생성기

  • 간단한 일대일 대응 연산을 통해 숫자를 암호화 시킴
  • 안전하지 않은 랜덤함수임으로 보안이 필요한 경우 사용하지 말것
  • 동작을 위해 key 사이즈는 4 ~ 8byte 로 할 것
import math
class RandSeq:
POS_BOX = [
[0x1, 0xb, 0x4, 0x9, 0xd, 0x8, 0xc, 0xa, 0xf, 0xe, 0x2, 0x7, 0x6, 0x0, 0x5, 0x3],
[0x7, 0xd, 0x9, 0x1, 0xf, 0xe, 0x8, 0xb, 0x6, 0xc, 0x3, 0x0, 0x2, 0x4, 0xa, 0x5],
]
def __init__ (self, key, start, stop, next_seq=0):
self.key = key
self.key_len = len(key)
self.start = start
self.stop = stop
diff = stop - start
bit_size = math.log2(diff + 1)
self.diff = diff
self.byte_size = math.ceil (bit_size / 8)
self.next_seq = next_seq
self.end_seq = 2 ** (self.byte_size * 8) - 1
def next(self):
while self.next_seq <= self.end_seq:
plain_num = self.next_seq.to_bytes(
self.byte_size, byteorder='little')
new_num = self._encrypt(plain_num)
self.next_seq += 1
if new_num >= self.start and new_num <= self.stop:
return new_num + self.start
return None
def shift_cir(self, val, shift_val, bit_size):
upper = (val << shift_val) % (1 << bit_size)
lower = val >> (bit_size - shift_val)
return upper | lower
def _encrypt(self, plain_bytes):
length = len(plain_bytes)
bit_size = len(plain_bytes) * 8
mask = 2**bit_size - 1
key_idx = 0
for i in range(8):
new_plain_bytes = []
for plain_byte in plain_bytes:
key = self.key[key_idx%self.key_len]
upper = plain_byte >> 4
lower = plain_byte & 0x0f
new_plain = self.POS_BOX[0][upper] << 4 | self.POS_BOX[1][lower]
new_plain ^= key
key_idx += 1
new_plain_bytes.append(new_plain)
plain_num = int.from_bytes(new_plain_bytes, byteorder="little")
plain_num += self.key_len
plain_num &= mask
plain_num = self.shift_cir(plain_num, 5, bit_size)
plain_bytes = plain_num.to_bytes(length, byteorder="little")
new_plain_bytes = []
for plain_byte in reversed(plain_bytes):
key = self.key[key_idx%self.key_len]
upper = plain_byte >> 4
lower = plain_byte & 0x0f
new_plain = self.POS_BOX[0][upper] << 4 | self.POS_BOX[1][lower]
new_plain ^= key
key_idx += 1
new_plain_bytes.append(new_plain)
plain_num = int.from_bytes(new_plain_bytes, byteorder="little")
plain_num += self.key_len
plain_num &= mask
plain_num = self.shift_cir(plain_num, 5, bit_size)
plain_bytes = plain_num.to_bytes(length, byteorder="little")
return plain_num
def main01():
randseq = RandSeq(b"Test", start=0, stop=2**4-1)
num_set = set()
for _ in range(2**8 - 1):
new_number = randseq.next()
if new_number is None:
break
if new_number in num_set:
print("error")
print(new_number)
num_set.add(new_number)
if __name__ == "__main__":
print("======== Start ========")
main01()
print("======== End ========")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment