defdigest(serial: int, key: str): real_digest = hashlib.md5(str(serial).zfill(8).encode()).digest() digest = bytes(real_digest[int(key[i], 16)] for i inrange(16))
bitstring = "".join(bin(i)[2:].zfill(8)[::-1] for i in digest)[::-1].zfill(6 * 23) computed = 0 while bitstring: work = int(bitstring[:23], 2) computed ^= work bitstring = bitstring[23:]
defcut_by_bottom_card(self): p = self.deck[-1] if p == self.JOKER_B: p = self.JOKER_A self.cut_deck(p)
defget_top_card_num(self): p = self.deck[0] if p == self.JOKER_B: p = self.JOKER_A return self.deck[p]
defdeck_hash(self): whileTrue: self.move_card(self.JOKER_A) self.move_card(self.JOKER_B) self.move_card(self.JOKER_B) self.swap_outside_joker() self.cut_by_bottom_card() p = self.get_top_card_num() if p notin (self.JOKER_A, self.JOKER_B): return p
defcreate_deck(self, key): self.deck = list(range(1, self.DECK_SIZE + 1)) for ch in key: self.deck_hash() c = char2num(ch) self.cut_deck(c)
defencode(self, key, plaintext): self.create_deck(key) ciphertext = "" for ch in plaintext: self.deck_hash() p = self.get_top_card_num() ciphertext += num2char(char2num(ch) + p) return ciphertext
defdecode(self, key, ciphertext): self.create_deck(key) plaintext = "" for ch in ciphertext: self.deck_hash() p = self.get_top_card_num() plaintext += num2char(char2num(ch) - p) return plaintext