def cast16(a): return ([set()]*16+a)[-16:] def cast32(a): return ([set()]*32+a)[-32:] def add8(a,b): rv = [set()]*9 for i in range(7,-1,-1): rv[i] = a[i]|b[i]|rv[i+1] return rv[:8] def add16(a,b): rv = [set()]*17 for i in range(15,-1,-1): rv[i] = a[i]|b[i]|rv[i+1] return rv[:16] def final_add16(a,b): "Unlike the previous, assume any bit with a single contributor is untouched" "This means that the bit will be sent to the carry whilst the previous carry will be the new value" c = set() rv = [set()]*16 for i in range(15,-1,-1): if len(a[i]) == 1 and a[i] == b[i]: rv[i] = c c = a[i] else: c = a[i]|b[i]|c rv[i] = a[i]|b[i]|c return rv[:16] def add32(a,b): rv = [set()]*33 for i in range(31,-1,-1): rv[i] = a[i]|b[i]|rv[i+1] return rv[:32] def rot8(a,b): return a[b:]+a[:b] def rot32(a,b): return a[b:]+a[:b] def xor8(a,b): return list(map(lambda a:a[0]|a[1],zip(a,b))) def xor16(a,b): return list(map(lambda a:a[0]|a[1],zip(a,b))) def xor32(a,b): return list(map(lambda a:a[0]|a[1],zip(a,b))) def petyaMix(a,b,c,r): return xor16(a,cast16(rot32(cast32(add16(b,c)),r))) def petyaSalsa20(): st = [[{(i,j)} for j in range(16)] for i in range(16)] cst = [[{(i,j)} for j in range(16)] for i in range(16)] for i in range(10): #MixCols st[ 4] = petyaMix(st[ 4],st[ 0],st[12], 7) st[ 8] = petyaMix(st[ 8],st[ 4],st[ 0], 9) st[12] = petyaMix(st[12],st[ 8],st[ 4],13) st[ 0] = petyaMix(st[ 0],st[12],st[ 8],18) st[ 9] = petyaMix(st[ 9],st[ 5],st[ 2], 7) st[13] = petyaMix(st[13],st[ 9],st[ 5], 9) st[ 1] = petyaMix(st[ 1],st[13],st[ 9],13) st[ 5] = petyaMix(st[ 5],st[ 1],st[13],18) st[14] = petyaMix(st[14],st[10],st[ 6], 7) st[ 2] = petyaMix(st[ 2],st[14],st[10], 9) st[ 6] = petyaMix(st[ 6],st[ 2],st[14],13) st[10] = petyaMix(st[10],st[ 6],st[ 2],18) st[ 3] = petyaMix(st[ 3],st[15],st[11], 7) st[ 7] = petyaMix(st[ 7],st[ 3],st[15], 9) st[11] = petyaMix(st[11],st[ 7],st[ 3],13) st[15] = petyaMix(st[15],st[11],st[ 7],18) #MixRows st[ 1] = petyaMix(st[ 1],st[ 0],st[ 3], 7) st[ 2] = petyaMix(st[ 2],st[ 1],st[ 0], 9) st[ 3] = petyaMix(st[ 3],st[ 2],st[ 1],13) st[ 0] = petyaMix(st[ 0],st[ 3],st[ 2],18) st[ 6] = petyaMix(st[ 6],st[ 5],st[ 4], 7) st[ 7] = petyaMix(st[ 7],st[ 6],st[ 5], 9) st[ 4] = petyaMix(st[ 4],st[ 7],st[ 6],13) st[ 5] = petyaMix(st[ 5],st[ 4],st[ 7],18) st[11] = petyaMix(st[11],st[10],st[ 9], 7) st[ 8] = petyaMix(st[ 8],st[11],st[10], 9) st[ 9] = petyaMix(st[ 9],st[ 8],st[11],13) st[10] = petyaMix(st[10],st[ 9],st[ 8],18) st[12] = petyaMix(st[12],st[15],st[14], 7) st[13] = petyaMix(st[13],st[12],st[15], 9) st[14] = petyaMix(st[14],st[13],st[12],13) st[15] = petyaMix(st[15],st[14],st[13],18) #return [final_add16(i,j) for i,j in zip(st,cst)] return [add16(i,j) for i,j in zip(st,cst)] #return st def salsa20Mix(a,b,c,r): return xor32(a,rot32(add32(b,c),r)) def salsa2(): st = [[{(i,j)} for j in range(32)] for i in range(16)] cst = [[{(i,j)} for j in range(32)] for i in range(16)] for i in range(1): #MixCols st[ 4] = salsa20Mix(st[ 4],st[ 0],st[12], 7) st[ 8] = salsa20Mix(st[ 8],st[ 4],st[ 0], 9) st[12] = salsa20Mix(st[12],st[ 8],st[ 4],13) st[ 0] = salsa20Mix(st[ 0],st[12],st[ 8],18) st[ 9] = salsa20Mix(st[ 9],st[ 5],st[ 2], 7) st[13] = salsa20Mix(st[13],st[ 9],st[ 5], 9) st[ 1] = salsa20Mix(st[ 1],st[13],st[ 9],13) st[ 5] = salsa20Mix(st[ 5],st[ 1],st[13],18) st[14] = salsa20Mix(st[14],st[10],st[ 6], 7) st[ 2] = salsa20Mix(st[ 2],st[14],st[10], 9) st[ 6] = salsa20Mix(st[ 6],st[ 2],st[14],13) st[10] = salsa20Mix(st[10],st[ 6],st[ 2],18) st[ 3] = salsa20Mix(st[ 3],st[15],st[11], 7) st[ 7] = salsa20Mix(st[ 7],st[ 3],st[15], 9) st[11] = salsa20Mix(st[11],st[ 7],st[ 3],13) st[15] = salsa20Mix(st[15],st[11],st[ 7],18) #MixRows st[ 1] = salsa20Mix(st[ 1],st[ 0],st[ 3], 7) st[ 2] = salsa20Mix(st[ 2],st[ 1],st[ 0], 9) st[ 3] = salsa20Mix(st[ 3],st[ 2],st[ 1],13) st[ 0] = salsa20Mix(st[ 0],st[ 3],st[ 2],18) st[ 6] = salsa20Mix(st[ 6],st[ 5],st[ 4], 7) st[ 7] = salsa20Mix(st[ 7],st[ 6],st[ 5], 9) st[ 4] = salsa20Mix(st[ 4],st[ 7],st[ 6],13) st[ 5] = salsa20Mix(st[ 5],st[ 4],st[ 7],18) st[11] = salsa20Mix(st[11],st[10],st[ 9], 7) st[ 8] = salsa20Mix(st[ 8],st[11],st[10], 9) st[ 9] = salsa20Mix(st[ 9],st[ 8],st[11],13) st[10] = salsa20Mix(st[10],st[ 9],st[ 8],18) st[12] = salsa20Mix(st[12],st[15],st[14], 7) st[13] = salsa20Mix(st[13],st[12],st[15], 9) st[14] = salsa20Mix(st[14],st[13],st[12],13) st[15] = salsa20Mix(st[15],st[14],st[13],18) return [add32(i,j) for i,j in zip(st,cst)] def salsa20(): st = [[{(i,j)} for j in range(32)] for i in range(16)] cst = [[{(i,j)} for j in range(32)] for i in range(16)] for i in range(10): #MixCols st[ 4] = salsa20Mix(st[ 4],st[ 0],st[12], 7) st[ 8] = salsa20Mix(st[ 8],st[ 4],st[ 0], 9) st[12] = salsa20Mix(st[12],st[ 8],st[ 4],13) st[ 0] = salsa20Mix(st[ 0],st[12],st[ 8],18) st[ 9] = salsa20Mix(st[ 9],st[ 5],st[ 2], 7) st[13] = salsa20Mix(st[13],st[ 9],st[ 5], 9) st[ 1] = salsa20Mix(st[ 1],st[13],st[ 9],13) st[ 5] = salsa20Mix(st[ 5],st[ 1],st[13],18) st[14] = salsa20Mix(st[14],st[10],st[ 6], 7) st[ 2] = salsa20Mix(st[ 2],st[14],st[10], 9) st[ 6] = salsa20Mix(st[ 6],st[ 2],st[14],13) st[10] = salsa20Mix(st[10],st[ 6],st[ 2],18) st[ 3] = salsa20Mix(st[ 3],st[15],st[11], 7) st[ 7] = salsa20Mix(st[ 7],st[ 3],st[15], 9) st[11] = salsa20Mix(st[11],st[ 7],st[ 3],13) st[15] = salsa20Mix(st[15],st[11],st[ 7],18) #MixRows st[ 1] = salsa20Mix(st[ 1],st[ 0],st[ 3], 7) st[ 2] = salsa20Mix(st[ 2],st[ 1],st[ 0], 9) st[ 3] = salsa20Mix(st[ 3],st[ 2],st[ 1],13) st[ 0] = salsa20Mix(st[ 0],st[ 3],st[ 2],18) st[ 6] = salsa20Mix(st[ 6],st[ 5],st[ 4], 7) st[ 7] = salsa20Mix(st[ 7],st[ 6],st[ 5], 9) st[ 4] = salsa20Mix(st[ 4],st[ 7],st[ 6],13) st[ 5] = salsa20Mix(st[ 5],st[ 4],st[ 7],18) st[11] = salsa20Mix(st[11],st[10],st[ 9], 7) st[ 8] = salsa20Mix(st[ 8],st[11],st[10], 9) st[ 9] = salsa20Mix(st[ 9],st[ 8],st[11],13) st[10] = salsa20Mix(st[10],st[ 9],st[ 8],18) st[12] = salsa20Mix(st[12],st[15],st[14], 7) st[13] = salsa20Mix(st[13],st[12],st[15], 9) st[14] = salsa20Mix(st[14],st[13],st[12],13) st[15] = salsa20Mix(st[15],st[14],st[13],18) return [add32(i,j) for i,j in zip(st,cst)] def xorCipher(): st = [[{(i,j)} for j in range(8)] for i in range(2)] nst = xor8(st[0],st[1]) return nst def caesarCipher(): st = [[{(i,j)} for j in range(8)] for i in range(2)] nst = add8(st[0],st[1]) return nst def myARX(): st = [[{(i,j)} for j in range(32)] for i in range(2)] st[0] = xor32(st[0],rot32(add32(st[0],st[1]),3)) st[1] = xor32(st[1],rot32(add32(st[0],st[1]),29)) return st st = xorCipher() for j in range(8): print(j, len(st[j]), sorted(list(st[j]))) st = caesarCipher() for j in range(8): print(j, len(st[j]), sorted(list(st[j]))) st = myARX() for i in range(2): for j in range(32): print(i, j, len(st[i][j]), sorted(list(st[i][j]))) st = petyaSalsa20() for i in range(16): for j in range(16): print(i, j, len(st[i][j])) st = salsa2() for i in range(16): for j in range(32): print(i, j, len(st[i][j])) st = salsa20() for i in range(16): for j in range(32): print(i, j, len(st[i][j]))