def check_block_delta_candidate(block_delta_i): with cmsh.Model() as model: hf: hfa.md4 = hfa.resolve(ALGO) # Ensure our delta is valid. block_delta = model.to_vec(block_delta_i, hf.block_size) # First construct two blocks with the given delta. block_1 = model.vec(hf.block_size) block_2 = model.vec(hf.block_size) model.add_assert((block_1 ^ block_2) == block_delta) # Assume we have any possible iv. This is safe even in the case # that iv_1 == iv_2 and our delta doesn't align with the blocks # under test (3, 11, 7, or 15), because we later calculate the # last possible round where we could have a difference and still # collide. iv_1 = model.vec(hf.state_size) iv_2 = model.vec(hf.state_size) # Compute the last 4 rounds and check if this is a viable candidate # (that we can generate a collision with). output_1s, _ = hf.eval(model, block_1, iv=iv_1, rounds=range(hf.rounds - 4, hf.rounds)) output_2s, _ = hf.eval(model, block_2, iv=iv_2, rounds=range(hf.rounds - 4, hf.rounds)) output_1 = model.join_vec(output_1s) output_2 = model.join_vec(output_2s) model.add_assert(output_1 == output_2) assert model.solve()
def bench_cmsh(num_vars, benchmark): cs = cmsh.Model() cv = [cs.var() for x in range(0, num_vars)] for clause in benchmark: i_left, op, i_right = clause left = cv[i_left] right = cv[i_right] if op == 'and': cs.add_assert(left & right) elif op == 'notand': cs.add_assert(-left & right) elif op == 'andnot': cs.add_assert(left & -right) elif op == 'notandnot': cs.add_assert(-left & -right) elif op == 'or': cs.add_assert(left | right) elif op == 'notor': cs.add_assert(-left | right) elif op == 'ornot': cs.add_assert(left | -right) elif op == 'notornot': cs.add_assert(-left | -right) sat = cs.solve() result = [] if sat: for var in cv: result.append(bool(var)) return sat, result
def test_mersenne_double_seed(): model = cmsh.Model() left_seed = model.vec(32) left_state = _mersenne.seed_rand(model, left_seed) left_index = -1 right_seed = model.vec(32) right_state = _mersenne.seed_rand(model, right_seed) right_index = -1 model.add_assert(left_seed != right_seed) left_value, left_index = _mersenne.gen_rand_long(model, left_state, left_index) right_value, right_index = _mersenne.gen_rand_long(model, right_state, right_index) model.add_assert(left_value == right_value) left_value, left_index = _mersenne.gen_rand_long(model, left_state, left_index) right_value, right_index = _mersenne.gen_rand_long(model, right_state, right_index) model.add_assert(left_value == right_value) assert model.solve() assert int(left_seed) == int(right_seed)
def build_collision(differential_path, offset, rounds): model = cmsh.Model() hf = md4.md4() hf.rounds = rounds block_1 = model.vec(512) block_1s = model.split_vec(block_1, 32) block_2 = model.vec(512) block_2s = model.split_vec(block_2, 32) output_1s, rounds_1s = hf.compute(model, block_1s) output_1 = model.join_vec(output_1s) rounds_1 = model.join_vec(rounds_1s) output_2s, rounds_2s = hf.compute(model, block_2s) output_2 = model.join_vec(output_2s) rounds_2 = model.join_vec(rounds_2s) model.add_assert(block_1 != block_2) model.add_assert(output_1 == output_2) model.add_assert((rounds_1 ^ rounds_2) == differential_path) if model.solve(): print("SAT", offset) print(hex(int(block_1))) print(hex(int(block_2))) print(hex(int(output_1))) print(hex(int(block_1 ^ block_2))) print(hex(int(rounds_1 ^ rounds_2))) else: print("UNSAT", offset)
def main(): model = cmsh.Model() hf = md4() iv_1 = model.vec(128) iv_2 = model.vec(128) block_1 = model.vec(512) block_2 = model.vec(512) output_1s, rounds_1s = hf.compute(model, block_1, iv=iv_1) output_1 = model.join_vec(output_1s) rounds_1 = model.join_vec(rounds_1s) output_2s, rounds_2s = hf.compute(model, block_2, iv=iv_2) output_2 = model.join_vec(output_2s) rounds_2 = model.join_vec(rounds_2s) model.add_assert(iv_1 != iv_2) model.add_assert(block_1 == 0) model.add_assert(block_2 == 0) model.add_assert(output_1 == output_2) if model.solve(): print("SAT", int(iv_1), int(iv_2)) else: print("UNSAT") model.cleanup()
def main(): m = cmsh.Model() av0 = m.vec(64) av1 = m.vec(64) av2 = m.vec(64) av3 = m.vec(64) bv0 = m.vec(64) bv1 = m.vec(64) bv2 = m.vec(64) bv3 = m.vec(64) av = m.join_vec([av0, av1, av2, av3]) bv = m.join_vec([bv0, bv1, bv2, bv3]) ar0, ar1, ar2, ar3 = _siphash.sipround(av0, av1, av2, av3) br0, br1, br2, br3 = _siphash.sipround(bv0, bv1, bv2, bv3) ar = m.join_vec([ar0, ar1, ar2, ar3]) br = m.join_vec([br0, br1, br2, br3]) eqv = m.to_vec([av[i] == bv[i] for i in range(0, len(av))]) m.add_assert(eqv.bit_sum() == 255) eqr = m.to_vec([ar[i] == br[i] for i in range(0, len(ar))]) m.add_assert(eqr.bit_sum() == 250) sat = m.solve() # assert not sat if sat: print(hex(int(av))) print(hex(int(bv))) print(hex(int(ar))) print(hex(int(br)))
def collision(block_differentials, rounds): model = cmsh.Model() algo = sha1() block_1 = model.vec(512) block_1s = model.split_vec(block_1, 32) block_2 = model.vec(512) block_2s = model.split_vec(block_2, 32) b1w = algo.block_schedule(model, block_1s) w_1 = model.join_vec(b1w) b2w = algo.block_schedule(model, block_2s) w_2 = model.join_vec(b2w) output_1s, _ = algo.compute(model, block_1s, rounds=rounds) output_1 = model.join_vec(output_1s) output_2s, _ = algo.compute(model, block_2s, rounds=rounds) output_2 = model.join_vec(output_2s) model.add_assert((block_1 ^ block_2) == to_int(block_differentials)) model.add_assert((output_1 ^ output_2) == 0) if model.solve(): print( "SAT", block_differentials, hex(int(block_1)), hex(int(block_2)), hex(int(block_1 ^ block_2)), hex(int(output_1)), ) else: print("UNSAT", block_differentials)
def test_md4_find_ivs(): model = cmsh.Model() h = md4() k1 = "839c7a4d7a92cb5678a5d5b9eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edd45e51fe39708bf9427e9c3e8b9" k2 = "839c7a4d7a92cbd678a5d529eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edc45e51fe39708bf9427e9c3e8b9" blocks_value_1 = list(map(lambda x: model.to_vector(x, width=32), split_hex(k1, 8))) blocks_value_2 = list(map(lambda x: model.to_vector(x, width=32), split_hex(k2, 8))) bv1 = model.join_vec(blocks_value_1) bv2 = model.join_vec(blocks_value_2) r_value_1, r_rounds_1 = h.compute(model, blocks_value_1) r_value_2, r_rounds_2 = h.compute(model, blocks_value_2) rv1 = model.join_vec(r_value_1) rsv1 = model.join_vec(r_rounds_1) blocks_1 = gen_blocks(model, 16, 32) blocks_2 = gen_blocks(model, 16, 32) b1 = model.join_vec(blocks_1) b2 = model.join_vec(blocks_2) iv_1_arr = gen_blocks(model, 4, 32) iv_2_arr = gen_blocks(model, 4, 32) iv_1 = model.join_vec(iv_1_arr) iv_2 = model.join_vec(iv_2_arr) # The blocks must differ... model.add_assert(b1 == bv1) model.add_assert(b2 == bv2) # But their MD4s must be the same result_1_arr, rounds_1_arr = h.compute(model, blocks_1, iv=iv_1_arr) result_2_arr, rounds_2_arr = h.compute(model, blocks_2, iv=iv_2_arr) result_1 = model.join_vec(result_1_arr) rounds_1 = model.join_vec(rounds_1_arr) result_2 = model.join_vec(result_2_arr) rounds_2 = model.join_vec(rounds_2_arr) model.add_assert(iv_1 == iv_2) model.add_assert(result_1 == rv1) model.add_assert(rounds_1 == rsv1) model.add_assert(result_1 == result_2) rr1 = model.join_vec(r_rounds_1) rr2 = model.join_vec(r_rounds_2) real_diff_path = rr1 ^ rr2 differential = rounds_1 ^ rounds_2 diff_path = differential == real_diff_path model.add_assume(diff_path) assert model.solve()
def main(): m = cmsh.Model() key = m.vec(128) r1 = _siphash.siphash(m, key, key, outlen=16, cROUNDS=1, dROUNDS=1) m.add_assert(r1 == key) assert m.solve() print(hex(int(key)))
def test_md4_find_existing_collision(): model = cmsh.Model() h = md4() k1 = "839c7a4d7a92cb5678a5d5b9eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edd45e51fe39708bf9427e9c3e8b9" k2 = "839c7a4d7a92cbd678a5d529eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edc45e51fe39708bf9427e9c3e8b9" blocks_value_1 = list(map(lambda x: model.to_vector(x, width=32), split_hex(k1, 8))) blocks_value_2 = list(map(lambda x: model.to_vector(x, width=32), split_hex(k2, 8))) indices = [] for i in range(0, len(blocks_value_1)): if blocks_value_1[i] != blocks_value_2[i]: indices.append(i) r_value_1, r_rounds_1 = h.compute(model, blocks_value_1) r_value_2, r_rounds_2 = h.compute(model, blocks_value_2) blocks_1 = gen_blocks(model, 16, 32) blocks_2 = gen_blocks(model, 16, 32) # The blocks must differ... different_blocks = blocks_1[0] != blocks_2[0] for i in range(1, len(blocks_1)): different_blocks = different_blocks | (blocks_1[i] != blocks_2[i]) model.add_assert(different_blocks) for i in range(0, len(blocks_1)): if i not in indices: model.add_assert(blocks_1[i] == blocks_value_1[i]) model.add_assert(blocks_2[i] == blocks_value_2[i]) # But their MD4s must be the same result_1, rounds_1 = h.compute(model, blocks_1) result_2, rounds_2 = h.compute(model, blocks_2) for i in range(0, 4): model.add_assert(result_2[i] == result_2[i]) for i in range(0, len(rounds_1)): r_differential = r_rounds_1[i] ^ r_rounds_2[i] differential = rounds_1[i] ^ rounds_2[i] model.add_assert(differential == r_differential) assert model.solve() variables = [] for index in indices: assert int(blocks_1[index]) == int(blocks_value_1[index]) assert int(blocks_1[index] != blocks_2[index]) variables.extend(blocks_1[index]) new_solution = model.negate_solution(variables) model.add_assert(new_solution) assert not model.solve()
def main(): mod = cmsh.Model() k1 = "839c7a4d7a92cb5678a5d5b9eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edd45e51fe39708bf9427e9c3e8b9" k2 = "839c7a4d7a92cbd678a5d529eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edc45e51fe39708bf9427e9c3e8b9" index = 1 blocks_value_1 = list( map(lambda x: mod.to_vector(x, width=32), split_hex(k1, 8))) blocks_value_2 = list( map(lambda x: mod.to_vector(x, width=32), split_hex(k2, 8))) r_value_1, r_rounds_1 = _md4.md4(mod, blocks_value_1) r_value_2, r_rounds_2 = _md4.md4(mod, blocks_value_2) assert r_rounds_1[0] == r_rounds_2[0] a, b, c, d = ( mod.vec(32), md4.md4.default_state[1], md4.md4.default_state[2], md4.md4.default_state[3], ) x_a, x_b, x_c, x_d = 0, 0, 0, 0 new_d_1, new_d_2 = r_rounds_1[1], r_rounds_2[1] x_new_d = new_d_1 ^ new_d_2 assert new_d_1 != new_d_2 # abcd # dabc new_x_1, new_x_2 = mod.vec(32), mod.vec(32) i_a, i_b, i_c, i_d = mod.vec(32), mod.vec(32), mod.vec(32), mod.vec(32) j_a, j_b, j_c, j_d = mod.vec(32), mod.vec(32), mod.vec(32), mod.vec(32) l_out_1 = _md4.md4_round([new_x_1], _md4.md4r1, [i_d, i_a, i_b, i_c], 0, 7)[1] l_out_2 = _md4.md4_round([new_x_2], _md4.md4r1, [j_d, j_a, j_b, j_c], 0, 7)[1] mod.add_assert(new_x_1 < new_x_2) mod.add_assert(i_a == j_a) mod.add_assert(i_b == j_b) mod.add_assert(i_c == j_c) mod.add_assert(i_d == j_d) mod.add_assert((l_out_1 ^ l_out_2) == (x_new_d)) sat = mod.solve() assert sat while sat: print( bin(int(i_a) ^ int(j_a)), bin(int(new_x_1) ^ int(new_x_2)), bin(int(x_new_d)), ) negated = mod.negate_solution(new_x_1 ^ new_x_2) mod.add_assert(negated) sat = mod.solve()
def test_known_value(): model = cmsh.Model() h = md4() block_hex = "8" + ("0" * 127) block = list(map(lambda x: model.to_vector(x, width=32), split_hex(block_hex))) res_hex = "31d6cfe0d16ae931b73c59d7e0c089c0" res_known = list(map(lambda x: model.to_vector(x, width=32), split_hex(res_hex))) res, _ = h.compute(model, block) assert list(map(int, res_known)) == list(map(int, res))
def test_md4_eval(): iv = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476] rounds = 16 block = [0x00000080] + [0x00000000] * 15 model = cmsh.Model() h = md4() output_state, intermediate = h.eval(model, block, iv, rounds) actual_state = list(map(int, output_state)) expected_state = [0xaddcb303, 0x3665f296, 0x8ee8f245, 0xa483a664] assert actual_state == expected_state
def test_known_value(): model = cmsh.Model() h = md5() block_hex = "8" + ("0" * 127) block = list( map(lambda x: model.to_vector(x, width=32), split_hex(block_hex))) res_hex = "d41d8cd98f00b204e9800998ecf8427e" res_known = list( map(lambda x: model.to_vector(x, width=32), split_hex(res_hex))) res, _ = h.compute(model, block) assert list(map(int, res_known)) == list(map(int, res))
def test_known_value(): model = cmsh.Model() h = sha1() block_hex = "80000000" + ("0" * 120) block = list( map(lambda x: model.to_vector(x, width=32), split_hex(block_hex))) res_hex = "da39a3ee5e6b4b0d3255bfef95601890afd80709" res_known = list( map(lambda x: model.to_vector(x, width=32), split_hex(res_hex))) res, _ = h.compute(model, block) assert list(map(int, res_known)) == list(map(int, res))
def test_md4_known_collision(): model = cmsh.Model() h = md4() k1 = "839c7a4d7a92cb5678a5d5b9eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edd45e51fe39708bf9427e9c3e8b9" k2 = "839c7a4d7a92cbd678a5d529eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edc45e51fe39708bf9427e9c3e8b9" blocks_1 = list(map(lambda x: model.to_vector(x, width=32), split_hex(k1, 8))) blocks_2 = list(map(lambda x: model.to_vector(x, width=32), split_hex(k2, 8))) assert list(map(int, blocks_1)) != list(map(int, blocks_2)) assert len(blocks_1) == 16 assert len(blocks_2) == 16 res_1, _ = h.compute(model, blocks_1) res_2, _ = h.compute(model, blocks_2) assert list(map(int, res_1)) == list(map(int, res_2))
def test_mersenne_known_test_vectors(): model = cmsh.Model() state = _mersenne.seed_rand(model, 1131464071) assert len(state) == 624 assert int(state[0]) == 1131464071 assert int(state[1]) == (69069 * int(state[0])) & 0xffffffff index = -1 value, index = _mersenne.gen_rand_long(model, state, index) assert int(value) == 3720971106 value, index = _mersenne.gen_rand_long(model, state, index) assert int(value) == 1185582179 value, index = _mersenne.gen_rand_long(model, state, index) assert int(value) == 2564798321 value, index = _mersenne.gen_rand_long(model, state, index) assert int(value) == 1931142078
def model(differential=[]): model = cmsh.Model() hf = hfa.md4() rounds = range(48 - 24, 48) iv_1 = model.vec(128) iv_2 = model.vec(128) block_1 = model.vec(512) block_1s = model.split_vec(block_1, 32) block_2 = model.vec(512) block_2s = model.split_vec(block_2, 32) output_1s, rounds_1s = hf.eval(model, block_1, iv_1, rounds) output_1 = model.join_vec(output_1s) output_2s, rounds_2s = hf.eval(model, block_2, iv_2, rounds) output_2 = model.join_vec(output_2s) for index in differential: model.add_assert(rounds_1s[index] == rounds_2s[index]) model.add_assert(output_1 == output_2) model.add_assert(block_1 < block_2) model.add_assert(iv_1 == iv_2) for i in range(48 - 4, 48): bi = hf.block_schedule[i] model.add_assert(block_1s[bi] == block_2s[bi]) if model.solve(): print(hex(int(iv_1)), hex(int(block_1)), hex(int(output_1))) print(hex(int(iv_2)), hex(int(block_2)), hex(int(output_2))) dif = [] for index, element_1 in enumerate(block_1s): element_2 = block_2s[index] dif.append(hex(int(element_1) ^ int(element_2))) print(dif) dif = [] dc = 0 for index, element_1 in enumerate(rounds_1s): element_2 = rounds_2s[index] if int(element_1) != int(element_2): dc += 1 dif.append(hex(int(element_1) ^ int(element_2))) print(dif, len(dif), dc)
def main(): with cmsh.Model() as model: # Model IV as 4x 32-bit vectors iv_1 = model.vec(128) iv_2 = model.vec(128) iv_1s = model.split_vec(iv_1, 32) iv_2s = model.split_vec(iv_2, 32) # Model final state as random 4x 32-bit vectors final_1 = model.vec(128) final_2 = model.vec(128) final_1s = model.split_vec(final_1, 32) final_2s = model.split_vec(final_2, 32) # Model output state as sum of iv and final output_1s = [ iv_1s[i] + final_1s[i] for i in range(0, len(iv_1s)) ] output_2s = [ iv_2s[i] + final_2s[i] for i in range(0, len(iv_2s)) ] output_1 = model.join_vec(output_1s) output_2 = model.join_vec(output_2s) model.add_assert(output_1 == output_2) # Compute IV and Final deltas: iv_d = iv_1 ^ iv_2 final_d = final_1 ^ final_2 # With iv_d == 0, the only solution is final_d == 0; i.e., it is # sufficient to ignore the outer addition in this construction. # # For each iv_d non-zero, there may be one or more answers. model.add_assert(iv_d.bit_sum() == 0) count = 0 while model.solve(): print(bin(int(iv_d)), bin(int(final_d))) new_iv_d = iv_d != int(iv_d) new_final_d = final_d != int(final_d) model.add_assert(new_iv_d | new_final_d) count += 1 if count % 100 == 0: print(count) print(count)
def validate_output(algo, o_model, block, iv, output, rounds): hf: hfa.md4 = hfa.fresh(algo) block = _normalize_(o_model, block) iv = _normalize_(o_model, iv) output = _normalize_(o_model, output) rounds = _normalize_(o_model, rounds) with cmsh.Model() as model: output_a, rounds_a = hf.compute(model, block, iv=iv, rounds=algo.rounds) output_a = _normalize_(model, output_a) rounds_a = _normalize_(model, rounds_a) assert output_a == output assert rounds_a == rounds
def test_known_value(): model = cmsh.Model() hf = siphash() key = model.to_vec(0x00, 128) block = [] assert int(hf.compute(model, key, block)) == 0x1E924B9D737700D7 key = model.to_vec(0x000102030405060708090A0B0C0D0E0F, 128) block = model.to_vec(0x000102030405060708090A0B0C0D0E, 120) assert int(hf.compute(model, key, block)) == 0xA129CA6149BE45E5 key = model.to_vec(0x00, 128) block = model.to_vec(0x48656C6C6F20776F726C64, 88) assert int(hf.compute(model, key, block)) == 0xC9E8A3021F3822D9 key = model.to_vec(0x00, 128) block = model.to_vec(0x3132333435363738313233, 88) assert int(hf.compute(model, key, block)) == 0xF95D77CCDB0649F
def test_mersenne_reverse_seed(): model = cmsh.Model() seed = model.vec(32) state = _mersenne.seed_rand(model, seed) index = -1 expectations = [ 3720971106, 1185582179, 2564798321, 1931142078, 1922624258, 2775287020, 184205937, 612490464, 3208490327, 1665128171, 1140358085, 3611116024, 953884115, 4099552555, 2606495820, 685898173 ] for expected in expectations: value, index = _mersenne.gen_rand_long(model, state, index) model.add_assert(value == expected) assert model.solve() assert int(seed) == 1131464071
def last_possible_round(block_delta_i): with cmsh.Model() as model: hf: hfa.md4 = hfa.resolve(ALGO) # Ensure our delta is valid and split it into block-sized chunks. block_delta = model.to_vec(block_delta_i, hf.block_size) block_deltas = model.split_vec(block_delta, hf.block_size // hf.blocks) last_round = 0 delta_indices = set() for round_num, block_index in enumerate(hf.block_schedule): if int(block_deltas[block_index]) != 0: delta_indices.add(block_index) last_round = round_num assert last_round != 0 return tuple(delta_indices), last_round
def test_save_collision(): with cmsh.Model() as model: hf = hfa.resolve('md4') k1 = "839c7a4d7a92cb5678a5d5b9eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edd45e51fe39708bf9427e9c3e8b9" k2 = "839c7a4d7a92cbd678a5d529eea5a7573c8a74deb366c3dc20a083b69f5d2a3bb3719dc69891e9f95e809fd7e8b23ba6318edc45e51fe39708bf9427e9c3e8b9" assert k1 != k2 known_shaped_1 = list( map(lambda x: model.to_vector(x, width=32), hfa.split_hex(k1, 8))) known_shaped_2 = list( map(lambda x: model.to_vector(x, width=32), hfa.split_hex(k2, 8))) block_1 = model.vec(hf.block_size) block_2 = model.vec(hf.block_size) output_1s, rounds_1s = hf.compute(model, block_1) output_2s, rounds_2s = hf.compute(model, block_2) output_1 = model.join_vec(output_1s) output_2 = model.join_vec(output_2s) rounds_1 = model.join_vec(rounds_1s) rounds_2 = model.join_vec(rounds_2s) model.add_assert(block_1 < block_2) model.add_assert(block_1 == model.join_vec(known_shaped_1)) model.add_assert(block_2 == model.join_vec(known_shaped_2)) model.add_assert(output_1 == output_2) assert model.solve() assert int(output_1) == int(output_2) db = hfd.Database(":memory:") default_state = model.join_vec( map(lambda x: model.to_vec(x, 32), hf.default_state)) hfd.create_table(db, hf) hfd.save_collision(db, hf, model, block_1, default_state, output_1, rounds_1, block_2, default_state, output_2, rounds_2) db.close()
def validate_collision(algo, o_model, block_1, iv_1, block_2, iv_2): hf: hfa.md4 = hfa.fresh(algo) block_1 = _normalize_(o_model, block_1) iv_1 = _normalize_(o_model, iv_1) block_2 = _normalize_(o_model, block_2) iv_2 = _normalize_(o_model, iv_2) with cmsh.Model() as model: o_1, r_1 = hf.compute(model, block_1, iv=iv_1, rounds=algo.rounds) o_2, r_2 = hf.compute(model, block_2, iv=iv_2, rounds=algo.rounds) for index, i_1 in enumerate(o_1): assert int(i_1) == int(o_2[index]) assert block_1 != block_2 or iv_1 != iv_2 if block_1 > block_2: return True if block_1 == block_2 and iv_1 > iv_2: return True return False
def main(): model = cmsh.Model() hf = md5() block_1 = model.vec(512) block_1s = model.split_vec(block_1, 32) output_1s, rounds_1s = hf.compute(model, block_1s) output_1 = model.join_vec(output_1s) rounds_1 = model.join_vec(rounds_1s) model.add_assert(block_1[0:32].bit_sum() == 4) model.add_assert(block_1[32:] == 0) model.add_assert(output_1 == 0xD41D8CD98F00B204E9800998ECF8427E) print("Solving...") if model.solve(): print("SAT", int(block_1)) else: print("UNSAT") model.cleanup()
def load_known_pieces(db, hf, block_delta_i): with cmsh.Model() as model: # Split into block-sized chunks so we can iterate over database data # and check if it is relevant for this solving session. block_delta = model.split_vec( model.to_vec(block_delta_i, hf.block_size), hf.block_size // hf.blocks) table_name = hf.name + "_collision_pieces" cols = [ 'round', 'h1_state', 'h2_state', 'd_state', 'h1_block', 'h2_block', 'd_block', 'h1_output', 'h2_output', 'd_output' ] for row in db.query(table_name, cols): row['round'] = int(row['round']) round_num = row['round'] block_index = hf.block_schedule[round_num] d_block = hex(int(block_delta[block_index]))[2:] if row['d_block'] != d_block: continue yield row
def find_differential(num_block_bits, state_differential): with cmsh.Model() as model: model.solver.config_timeout(30) hf: hfa.md4 = hfa.resolve('md4') raw_block_1 = model.vec(32) raw_block_2 = model.vec(32) model.add_assert((raw_block_1 ^ raw_block_2).bit_sum() == num_block_bits) block_1 = [ raw_block_1 ] * (hf.block_size // 32) block_2 = [ raw_block_1 ] * (hf.block_size // 32) for round_index in range(0, hf.rounds): iv_1 = model.vec(hf.state_size) iv_1s = model.split_vec(iv_1, hf.int_size) iv_2 = model.vec(hf.state_size) iv_2s = model.split_vec(iv_2, hf.int_size) model.add_assert((iv_1s[0] ^ iv_2s[0]) == state_differential) for index, state_1 in enumerate(iv_1s[1:], start=1): model.add_assert(state_1 == iv_2s[index]) output_1s, _ = hf.eval(model, block_1, iv=iv_1s, rounds=[round_index]) output_2s, _ = hf.eval(model, block_2, iv=iv_2s, rounds=[round_index]) output_1 = model.join_vec(output_1s) output_2 = model.join_vec(output_2s) model.add_assert(output_1 == output_2) sat = model.solve() if sat is True: print(f"{state_differential} - SAT") elif sat is None: print(f"{state_differential} - timeout")
def build_collision(family, rounds): model = cmsh.Model() hf = md4() hf.rounds = rounds block_1 = model.vec(512) block_1s = model.split_vec(block_1, 32) block_2 = model.vec(512) block_2s = model.split_vec(block_2, 32) output_1s, rounds_1s = hf.compute(model, block_1s) output_1 = model.join_vec(output_1s) rounds_1 = model.join_vec(rounds_1s) output_2s, rounds_2s = hf.compute(model, block_2s) output_2 = model.join_vec(output_2s) rounds_2 = model.join_vec(rounds_2s) model.add_assert(block_1 != block_2) model.add_assert(output_1 == output_2) assert len(rounds_1s) == rounds assert len(rounds_2s) == rounds for r_index in range(0, rounds): if r_index in family: model.add_assert((rounds_1s[r_index] ^ rounds_2s[r_index]) != 0) else: model.add_assert((rounds_1s[r_index] ^ rounds_2s[r_index]) == 0) if model.solve(): print("SAT", family, rounds) else: print("UNSAT", family, rounds) model.cleanup()
def main(): m = cmsh.Model() v0 = m.vec(64) v1 = m.vec(64) v2 = m.vec(64) v3 = m.vec(64) r0, r1, r2, r3 = _siphash.sipround(v0, v1, v2, v3) o0, o1, o2, o3 = _siphash.sipround(r0, r1, r2, r3) m.add_assert(v0 == o0) m.add_assert(v1 == o1) m.add_assert(v2 == o2) m.add_assert(v3 == o3) sat = m.solve() assert sat while sat: print(hex(int(v0)), hex(int(v1)), hex(int(v2)), hex(int(v3))) joined = m.join_vec([v0, v1, v2, v3]) negated = m.negate_solution(joined) m.add_assert(negated) sat = m.solve()