#!/usr/bin/env python

# requires a cleaned output of angr_tgt.py for the lfsr function
# split up that output into one line per bit, and for that bit only
# keep the indexes of the bits that contribute to this particular bit
# in the previous state.

with open('lfsr-next-bits.txt','r') as f:
    bits = [list(sorted(int(idx) for idx in line.split() if idx)) for line in reversed(f.readlines())]

print('\n'.join(str(x) for x in bits))

def walk(bit, c):
    c.append(bit)
    for b in bits[bit]:
        if b in c: continue
        c=walk(b,c)
    return c

from PIL import Image, ImageDraw, ImageColor
#scale = 10
scale = 80
outlinewidth = scale//10
im = Image.new('RGB', (scale * 16, scale * 8), (255, 255, 255))
draw = ImageDraw.Draw(im)
# Palette from https://rmogi.wordpress.com/2019/11/28/print-friendly-colour-palette/
cgrad = ['#FFEDA0', '#D4B9DA', '#238B45', '#FD8D3C', '#08306B']
cgrad = [ImageColor.getrgb(x) for x in cgrad]
colors = {0: cgrad[1], 2: cgrad[2], 4: cgrad[3], 6: cgrad[4]}
secondary= {95: cgrad[3], 103: cgrad[3], 111: cgrad[3], 119: cgrad[3], 127: cgrad[3], 109: cgrad[2], 117: cgrad[2], 125: cgrad[2], 123: cgrad[1]}
fill={15: cgrad[0], 15-7: cgrad[0]}

seen=set()
drawn=set()
for bit in range(128):
    b = tuple(sorted(walk(bit,[])))
    if b in seen: continue
    seen.add(b)
    for p in b:
        if p in drawn: continue

        draw.rectangle(
            (((127-p)//8)*scale, (p%8) * scale,
             ((127-p)//8)*scale + (scale-1), (p%8) * scale + (scale-1)),
            fill=colors.get(bit, cgrad[0]),
            outline=fill.get(p//8, (0, 0, 0)),
            width=outlinewidth)
        if secondary.get(bit):
            draw.polygon(
                [(((127-p)//8)*scale + outlinewidth, (p%8) * scale  + outlinewidth),
                 (((127-p)//8)*scale + outlinewidth, (p%8) * scale + (scale-1) - outlinewidth),
                 (((127-p)//8)*scale + (scale-1) - outlinewidth, (p%8) * scale + (scale-1) - outlinewidth)],
                fill=secondary[bit])

        drawn.add(p)
    print(bit, len(b), b)

im.save('lfsr.png', quality=95)

# outputs
"""
0 32 (0, 1, 8, 9, 16, 17, 24, 25, 32, 33, 40, 41, 48, 49, 56, 57, 64, 65, 72, 73, 80, 81, 88, 89, 96, 97, 104, 105, 112, 113, 120, 121)
2 31 (2, 3, 10, 11, 18, 19, 26, 27, 34, 35, 42, 43, 50, 51, 58, 59, 66, 67, 74, 75, 82, 83, 90, 91, 98, 99, 106, 107, 114, 115, 122)
4 29 (4, 5, 12, 13, 20, 21, 28, 29, 36, 37, 44, 45, 52, 53, 60, 61, 68, 69, 76, 77, 84, 85, 92, 93, 100, 101, 108, 116, 124)
6 27 (6, 7, 14, 15, 22, 23, 30, 31, 38, 39, 46, 47, 54, 55, 62, 63, 70, 71, 78, 79, 86, 87, 94, 102, 110, 118, 126)

95 28  (6, 7, 14, 15, 22, 23, 30, 31, 38, 39, 46, 47, 54, 55, 62, 63, 70, 71, 78, 79, 86, 87, 94, 95, 102, 110, 118, 126)
103 28 (6, 7, 14, 15, 22, 23, 30, 31, 38, 39, 46, 47, 54, 55, 62, 63, 70, 71, 78, 79, 86, 87, 94, 102, 103, 110, 118, 126)
109 30 (4, 5, 12, 13, 20, 21, 28, 29, 36, 37, 44, 45, 52, 53, 60, 61, 68, 69, 76, 77, 84, 85, 92, 93, 100, 101, 108, 109, 116, 124)
111 28 (6, 7, 14, 15, 22, 23, 30, 31, 38, 39, 46, 47, 54, 55, 62, 63, 70, 71, 78, 79, 86, 87, 94, 102, 110, 111, 118, 126)
117 30 (4, 5, 12, 13, 20, 21, 28, 29, 36, 37, 44, 45, 52, 53, 60, 61, 68, 69, 76, 77, 84, 85, 92, 93, 100, 101, 108, 116, 117, 124)
119 28 (6, 7, 14, 15, 22, 23, 30, 31, 38, 39, 46, 47, 54, 55, 62, 63, 70, 71, 78, 79, 86, 87, 94, 102, 110, 118, 119, 126)
123 32 (2, 3, 10, 11, 18, 19, 26, 27, 34, 35, 42, 43, 50, 51, 58, 59, 66, 67, 74, 75, 82, 83, 90, 91, 98, 99, 106, 107, 114, 115, 122, 123)
125 30 (4, 5, 12, 13, 20, 21, 28, 29, 36, 37, 44, 45, 52, 53, 60, 61, 68, 69, 76, 77, 84, 85, 92, 93, 100, 101, 108, 116, 124, 125)
127 28 (6, 7, 14, 15, 22, 23, 30, 31, 38, 39, 46, 47, 54, 55, 62, 63, 70, 71, 78, 79, 86, 87, 94, 102, 110, 118, 126, 127)
"""
