#!/usr/bin/env python3
from pathlib import Path
from zipfile import ZipFile
import hashlib, json, re, sys

ENCRYPT_GCC = [22, 11, 3, 26, 30, 16, 1, 12, 10, 7, 31, 21, 5, 19, 13, 28, 2, 27, 8, 20, 29, 18, 4, 14, 25, 17, 23, 0, 6, 15, 24, 9]
DECRYPT_GCC = [21, 27, 11, 16, 14, 28, 7, 1, 5, 31, 20, 12, 18, 10, 6, 26, 2, 8, 17, 24, 30, 23, 0, 13, 22, 3, 19, 9, 29, 15, 25, 4]
KEY = 0xA7A7A7A7

def swap_bits(word, mapping):
    out = 0
    for bit in mapping:
        out = (out << 1) | ((word >> bit) & 1)
    return out

def transform(data, decrypt):
    mapping = DECRYPT_GCC if decrypt else ENCRYPT_GCC
    out = bytearray(len(data))
    for i in range(0, len(data), 4):
        word = int.from_bytes(data[i:i+4], 'big')
        if decrypt:
            word = swap_bits(word, mapping) ^ KEY
        else:
            word = swap_bits(word ^ KEY, mapping)
        out[i:i+4] = word.to_bytes(4, 'big')
    return bytes(out)

def read_bin(path):
    with ZipFile(path) as zf:
        names = [n for n in zf.namelist() if n.lower().endswith('.bin')]
        if len(names) != 1:
            raise SystemExit(f'{path}: expected one BIN, found {names}')
        return names[0], zf.read(names[0])

def main(argv):
    if len(argv) != 3:
        raise SystemExit('usage: verify_gcc4241n_tsop_transform.py A100.zip A101.zip')
    results = []
    for revision, path in [('A100', Path(argv[1])), ('A101', Path(argv[2]))]:
        member, encrypted = read_bin(path)
        plain = transform(encrypted, True)
        round_trip = transform(plain, False)
        results.append({
            'revision': revision,
            'archive': str(path),
            'member': member,
            'encrypted_sha256': hashlib.sha256(encrypted).hexdigest(),
            'plaintext_sha256': hashlib.sha256(plain).hexdigest(),
            'round_trip_exact': round_trip == encrypted,
            'identity_found': (f'GCC-4241N{revision}'.encode() in plain),
        })
    print(json.dumps({'results': results, 'status': 'pass' if all(x['round_trip_exact'] and x['identity_found'] for x in results) else 'fail'}, indent=2))

if __name__ == '__main__':
    main(sys.argv)
