cp: int = int(pow(q, -1) % p)
cq: int = int(pow(p, -1) % q)
dp: int = d % (p - 1)
dq: int = d % (q - 1)
def decrypt_chinese_rest(x):
    xp: int = x % p
    xq: int = x % q
    # 2
    print('pow pow powpow', type(xq))
    yp: int = pow(xp,dp) % p
    yq: int = pow(xq,dq) % q
    # 3
    print('c done')
    return q * cp * yp + p * cq * yq % n


def decrypt_naive(x):
    result: int = pow(x, d)
    print(type(result))
    result: int = result % n
    print(type(result))
    print('n done')
    return result

def benchmark_chunky(x):
        results = []
        i = 0
        for c in bytearray(x):
            results.append(benchmark(i, c))
            i += 1
        elapsed_naive = 0.0
        elapsed_chinese = 0.0
        for result in results:
            elapsed_naive = elapsed_naive + result[0]
            elapsed_chinese = elapsed_chinese + result[1]
        print('----------------------------------------------------\n',
              elapsed_naive, elapsed_chinese, elapsed_naive - elapsed_chinese, 1.0 - (elapsed_chinese / elapsed_naive))

def benchmark(i, x):
    encrypt = key.encrypt(x, None)[0]
    start_chinese = time()
    result_chinese = decrypt_chinese_rest(encrypt)
    stop_chinese = time()
    elapsed_chinese = stop_chinese - start_chinese

    start_naive = time()
    result_naive = decrypt_naive(encrypt)
    stop_naive = time()
    elapsed_naive = stop_naive - start_naive

    if result_chinese != x or result_naive != x:
        raise AssertionError('decryption unsuccessful, naive %i, chinese: %i' % (result_naive ,result_chinese))

    print(i + 1, elapsed_naive, elapsed_chinese, elapsed_naive - elapsed_chinese, 1.0 - (elapsed_chinese/elapsed_naive))
    return elapsed_naive, elapsed_chinese

# benchmark
print('\t'.join(['#', 'naive duration', 'chinese duration', 'difference', '%']))
for i in range(50):
    benchmark_chunky(number.getRandomInteger(2048))