def flip_d5_bit(X, d5i, check=True): s0 = md4.INITIAL_STATE [s1, s2, s3, s4] = md4.do_round1(X, s0) a2, _, _, _ = s2 # d5i - 5 + 3 a2_new = flip_nth_bit(a2, d5i - 2) s2_new = [a2_new, s2[1], s2[2], s2[3]] X_new = invert_round1(s0, [s1, s2_new, s3, s4]) if not check: return X_new for i in list(range(0, 4)) + list(range(9, 16)): assert_word_eq(X_new[i], X[i]) round1_states_new = md4.do_round1(X_new, s0) expected_round1_states = [s1, s2_new, s3, s4] for i in range(4): if round1_states_new[i] != expected_round1_states[i]: raise Exception('expected s[{}]={}, got {}'.format(i, dump_s(expected_round1_states[i]), dump_s(round1_states_new[i]))) round2_states_new = md4.do_round2(X_new, round1_states_new[-1]) [s5, s6, s7, s8] = md4.do_round2(X, s4) expected_round1_states = [round2_states_new[0], s6, s7, s8] _, _, _, d5_new = round2_states_new[0] _, _, _, d5 = s5 if nth_bit(d5_new, d5i) == nth_bit(d5, d5i): raise Exception('d5 bit {} not flipped'.format(d5i)) return X_new
def flip_a5_bit(X, a5i, check=True): s0 = md4.INITIAL_STATE [s1, s2, s3, s4] = md4.do_round1(X, s0) a1, _, _, _ = s1 # a5i - 3 + 3 a1_new = flip_nth_bit(a1, a5i) s1_new = [a1_new, s1[1], s1[2], s1[3]] X_new = invert_round1(s0, [s1_new, s2, s3, s4]) if not check: return X_new for i in range(5, 16): assert_word_eq(X_new[i], X[i]) round1_states_new = md4.do_round1(X_new, s0) expected_round1_states = [s1_new, s2, s3, s4] for i in range(4): if round1_states_new[i] != expected_round1_states[i]: raise Exception('expected s[{}]={}, got {}'.format(i, dump_s(expected_round1_states[i]), dump_s(round1_states_new[i]))) round2_states_new = md4.do_round2(X_new, round1_states_new[-1]) [s5, s6, s7, s8] = md4.do_round2(X, s4) expected_round1_states = [round2_states_new[0], s6, s7, s8] a5_new, _, _, _ = round2_states_new[0] a5, _, _, _ = s5 if nth_bit(a5_new, a5i) == nth_bit(a5, a5i): raise Exception('a5 bit {} not flipped'.format(a5i)) return X_new
def test_invert_round1(): for i in range(1000): X = randX() state = md4.do_round1(X, md4.INITIAL_STATE) X2 = invert_round1(md4.INITIAL_STATE, state) if X != X2: raise Exception('expected {}, got {}'.format(X, X2))
def do_multi_step_mod(words, check=True): round1_states = md4.do_round1(words) _, _, _, c4 = round1_states[-1] words = do_a5_mod(words, 18, nth_bit(c4, 18), check) words = do_a5_mod(words, 25, 1, check) words = do_a5_mod(words, 26, 0, check) words = do_a5_mod(words, 28, 1, check) words = do_a5_mod(words, 31, 1, check) if check: assert_collidable_round1(words, extra=False) assert_collidable_round2_a5(words) round1_states = md4.do_round1(words) _, b4, _, _ = round1_states[-1] round2_states = md4.do_round2(words, round1_states[-1]) a5, b5, c5, d5 = round2_states[0] words = do_d5_mod(words, 18, nth_bit(a5, 18), check) words = do_d5_mod(words, 25, nth_bit(b4, 25), check) words = do_d5_mod(words, 26, nth_bit(b4, 26), check) words = do_d5_mod(words, 28, nth_bit(b4, 28), check) if check: assert_collidable_round1(words, extra=False) assert_collidable_round2_a5(words) assert_collidable_round2_d5(words) round1_states = md4.do_round1(words) _, b4, _, _ = round1_states[-1] round2_states = md4.do_round2(words, round1_states[-1]) a5, b5, c5, d5 = round2_states[0] words = do_c5_mod(words, 25, nth_bit(d5, 25), check) words = do_c5_mod(words, 26, nth_bit(d5, 26), check) # skip 28 for now # words = do_c5_mod(words, 28, nth_bit(d5, 28), check) words = do_c5_mod(words, 31, nth_bit(d5, 31), check) if check: assert_collidable_round1(words, extra=False) assert_collidable_round2_a5(words) assert_collidable_round2_d5(words) assert_collidable_round2_c5(words) return words
def flip_c5_bit(X, c5i, check=True): s0 = md4.INITIAL_STATE [s1, s2, s3, s4] = md4.do_round1(X, s0) _, a2, _, d2 = s2 # ? d2_new = flip_nth_bit(d2, c5i - 9) if c5i == 28: a2_new = flip_nth_bit(a2, c5i - 9) else: a2_new = a2 s2_new = [s2[0], a2_new, s2[2], d2_new] X_new = invert_round1(s0, [s1, s2_new, s3, s4]) if not check: return X_new for i in list(range(0, 4)) + list(range(12, 16)): assert_word_eq(X_new[i], X[i]) if a2_new == a2: for i in [4, 10, 11]: assert_word_eq(X_new[i], X[i]) [s5, s6, s7, s8] = md4.do_round2(X, s4) round1_states_new = md4.do_round1(X_new, s0) expected_round1_states = [s1, s2_new, s3, s4] for i in range(4): if round1_states_new[i] != expected_round1_states[i]: raise Exception('expected s[{}]={}, got {}'.format( i, dump_s(expected_round1_states[i]), dump_s(round1_states_new[i]))) round2_states_new = md4.do_round2(X_new, round1_states_new[-1]) [s5, s6, s7, s8] = md4.do_round2(X, s4) expected_round1_states = [round2_states_new[0], s6, s7, s8] _, _, c5_new, _ = round2_states_new[0] _, _, c5, _ = s5 if nth_bit(c5_new, c5i) == nth_bit(c5, c5i): raise Exception('c5 bit {} not flipped'.format(c5i)) return X_new
def assert_collidable_round3(words): round1_states = md4.do_round1(words) round2_states = md4.do_round2(words, round1_states[-1]) round3_states = md4.do_round3(words, round2_states[-1]) _, b9, _, _ = round3_states[0] a10, _, _, _ = round3_states[1] assert_bit1(b9, 32, 1) assert_bit1(a10, 32, 1)
def do_a5_mod(words, a5i, b, check=True): if check: assert_collidable_round1(words, extra=False) round1_states = md4.do_round1(words) round2_states = md4.do_round2(words, round1_states[-1]) a5, b5, c5, d5 = round2_states[0] if nth_bit(a5, a5i) == b: return words words_new = flip_a5_bit(words, a5i, check) if check: assert_collidable_round1(words_new, extra=False) assert_collidable_round2_a5(words_new, a5i) return words_new
def assert_collidable_round2_d5(words, d5i=None): round1_states = md4.do_round1(words) a4, b4, c4, d4 = round1_states[-1] round2_states = md4.do_round2(words, round1_states[-1]) a5, b5, c5, d5 = round2_states[0] if d5i is None or d5i >= 18: assert_bit(d5, 18, nth_bit(a5, 18)) if d5i is None or d5i >= 25: assert_bit(d5, 25, nth_bit(b4, 25)) if d5i is None or d5i >= 26: assert_bit(d5, 26, nth_bit(b4, 26)) if d5i is None or d5i >= 28: assert_bit(d5, 28, nth_bit(b4, 28))
def assert_collidable_round2_c5(words, c5i=False): round1_states = md4.do_round1(words) a4, b4, c4, d4 = round1_states[-1] round2_states = md4.do_round2(words, round1_states[-1]) a5, b5, c5, d5 = round2_states[0] if c5i is None or c5i >= 25: assert_bit(c5, 25, nth_bit(d5, 25)) if c5i is None or c5i >= 26: assert_bit(c5, 26, nth_bit(d5, 26)) # skip 28 for now # if c5i is None or c5i >= 28: # assert_bit(c5, 28, nth_bit(d5, 28)) if c5i is None or c5i >= 31: assert_bit(c5, 31, nth_bit(d5, 31))
def assert_collidable_round2(words): round1_states = md4.do_round1(words) a4, b4, c4, d4 = round1_states[-1] round2_states = md4.do_round2(words, round1_states[-1]) a5, b5, c5, d5 = round2_states[0] a6, b6, c6, d6 = round2_states[1] assert_bit1(a5, 19, c4, 19) assert_bit1(a5, 26, 1) assert_bit1(a5, 27, 0) assert_bit1(a5, 29, 1) assert_bit1(a5, 32, 1) assert_bit1(d5, 19, a5, 19) assert_bit1(d5, 26, b4, 26) assert_bit1(d5, 27, b4, 27) assert_bit1(d5, 29, b4, 29) assert_bit1(d5, 32, b4, 32) assert_bit1(c5, 26, d5, 26) assert_bit1(c5, 27, d5, 27) assert_bit1(c5, 29, d5, 29) assert_bit1(c5, 30, d5, 30) assert_bit1(c5, 32, d5, 32) assert_bit1(b5, 29, c5, 29) assert_bit1(b5, 30, 1) assert_bit1(b5, 32, 0) assert_bit1(a6, 29, 1) assert_bit1(a6, 32, 1) # From https://eprint.iacr.org/2005/151.pdf assert_bit1(a6, 30, 0) assert_bit1(d6, 29, b5, 29) assert_bit1(c6, 29, d6, 29) assert_bit1(c6, 30, (1 + nth_bit(d6, 30 - 1)) % 2) assert_bit1(c6, 32, (1 + nth_bit(d6, 32 - 1)) % 2)
def assert_collidable_round2_a5(words, a5i=None): round1_states = md4.do_round1(words) a4, b4, c4, d4 = round1_states[-1] round2_states = md4.do_round2(words, round1_states[-1]) a5, b5, c5, d5 = round2_states[0] if a5i is None or a5i >= 18: assert_bit(a5, 18, nth_bit(c4, 18)) if a5i is None or a5i >= 25: assert_bit(a5, 25, 1) if a5i is None or a5i >= 26: assert_bit(a5, 26, 0) if a5i is None or a5i >= 28: assert_bit(a5, 28, 1) if a5i is None or a5i >= 31: assert_bit(a5, 31, 1)
def do_single_step_mod(words, extra=True): a0, b0, c0, d0 = md4.INITIAL_STATE states = md4.do_round1(words) a1, b1, c1, d1 = states[0] a2, b2, c2, d2 = states[1] a3, b3, c3, d3 = states[2] a4, b4, c4, d4 = states[3] a1 = set_nth_bit(a1, 6, nth_bit(b0, 6)) d1 = set_nth_bit(d1, 6, 0) d1 = set_nth_bit(d1, 7, nth_bit(a1, 7)) d1 = set_nth_bit(d1, 10, nth_bit(a1, 10)) c1 = set_nth_bit(c1, 6, 1) c1 = set_nth_bit(c1, 7, 1) c1 = set_nth_bit(c1, 10, 0) c1 = set_nth_bit(c1, 25, nth_bit(d1, 25)) b1 = set_nth_bit(b1, 6, 1) b1 = set_nth_bit(b1, 7, 0) b1 = set_nth_bit(b1, 10, 0) b1 = set_nth_bit(b1, 25, 0) if extra: b1 = set_nth_bit(b1, 19, 0) a2 = set_nth_bit(a2, 7, 1) a2 = set_nth_bit(a2, 10, 1) a2 = set_nth_bit(a2, 25, 0) a2 = set_nth_bit(a2, 13, nth_bit(b1, 13)) if extra: for i in [16, 17, 19, 22]: a2 = set_nth_bit(a2, i, nth_bit(b1, i)) d2 = set_nth_bit(d2, 13, 0) d2 = set_nth_bit(d2, 18, nth_bit(a2, 18)) d2 = set_nth_bit(d2, 19, nth_bit(a2, 19)) d2 = set_nth_bit(d2, 20, nth_bit(a2, 20)) d2 = set_nth_bit(d2, 21, nth_bit(a2, 21)) d2 = set_nth_bit(d2, 25, 1) if extra: for i in [16, 17, 19, 22]: d2 = set_nth_bit(d2, i, 0) c2 = set_nth_bit(c2, 12, nth_bit(d2, 12)) c2 = set_nth_bit(c2, 13, 0) c2 = set_nth_bit(c2, 14, nth_bit(d2, 14)) c2 = set_nth_bit(c2, 18, 0) c2 = set_nth_bit(c2, 19, 0) c2 = set_nth_bit(c2, 20, 1) c2 = set_nth_bit(c2, 21, 0) if extra: for i in [16, 17, 19, 22]: c2 = set_nth_bit(c2, i, 0) b2 = set_nth_bit(b2, 12, 1) b2 = set_nth_bit(b2, 13, 1) b2 = set_nth_bit(b2, 14, 0) b2 = set_nth_bit(b2, 16, nth_bit(c2, 16)) b2 = set_nth_bit(b2, 18, 0) b2 = set_nth_bit(b2, 19, 0) b2 = set_nth_bit(b2, 20, 0) b2 = set_nth_bit(b2, 21, 0) if extra: for i in [16, 17, 19, 22]: b2 = set_nth_bit(b2, i, 0) a3 = set_nth_bit(a3, 12, 1) a3 = set_nth_bit(a3, 13, 1) a3 = set_nth_bit(a3, 14, 1) a3 = set_nth_bit(a3, 16, 0) a3 = set_nth_bit(a3, 18, 0) a3 = set_nth_bit(a3, 19, 0) a3 = set_nth_bit(a3, 20, 0) a3 = set_nth_bit(a3, 22, nth_bit(b2, 22)) a3 = set_nth_bit(a3, 21, 1) a3 = set_nth_bit(a3, 25, nth_bit(b2, 25)) d3 = set_nth_bit(d3, 12, 1) d3 = set_nth_bit(d3, 13, 1) d3 = set_nth_bit(d3, 14, 1) d3 = set_nth_bit(d3, 16, 0) d3 = set_nth_bit(d3, 19, 0) d3 = set_nth_bit(d3, 20, 1) d3 = set_nth_bit(d3, 21, 1) d3 = set_nth_bit(d3, 22, 0) d3 = set_nth_bit(d3, 25, 1) d3 = set_nth_bit(d3, 29, nth_bit(a3, 29)) c3 = set_nth_bit(c3, 16, 1) c3 = set_nth_bit(c3, 19, 0) c3 = set_nth_bit(c3, 20, 0) c3 = set_nth_bit(c3, 21, 0) c3 = set_nth_bit(c3, 22, 0) c3 = set_nth_bit(c3, 25, 0) c3 = set_nth_bit(c3, 29, 1) c3 = set_nth_bit(c3, 31, nth_bit(d3, 31)) b3 = set_nth_bit(b3, 19, 0) b3 = set_nth_bit(b3, 20, 1) b3 = set_nth_bit(b3, 21, 1) b3 = set_nth_bit(b3, 22, nth_bit(c3, 22)) b3 = set_nth_bit(b3, 25, 1) b3 = set_nth_bit(b3, 29, 0) b3 = set_nth_bit(b3, 31, 0) a4 = set_nth_bit(a4, 22, 0) a4 = set_nth_bit(a4, 25, 0) a4 = set_nth_bit(a4, 26, nth_bit(b3, 26)) a4 = set_nth_bit(a4, 28, nth_bit(b3, 28)) a4 = set_nth_bit(a4, 29, 1) a4 = set_nth_bit(a4, 31, 0) d4 = set_nth_bit(d4, 22, 0) d4 = set_nth_bit(d4, 25, 0) d4 = set_nth_bit(d4, 26, 1) d4 = set_nth_bit(d4, 28, 1) d4 = set_nth_bit(d4, 29, 0) d4 = set_nth_bit(d4, 31, 1) c4 = set_nth_bit(c4, 18, nth_bit(d4, 18)) c4 = set_nth_bit(c4, 22, 1) c4 = set_nth_bit(c4, 25, 1) c4 = set_nth_bit(c4, 26, 0) c4 = set_nth_bit(c4, 28, 0) c4 = set_nth_bit(c4, 29, 0) b4 = set_nth_bit(b4, 18, 0) b4 = set_nth_bit(b4, 25, 1) b4 = set_nth_bit(b4, 26, 1) b4 = set_nth_bit(b4, 28, 1) b4 = set_nth_bit(b4, 29, 0) # From https://eprint.iacr.org/2005/151.pdf b4 = set_nth_bit(b4, 31, nth_bit(c4, 31)) s0 = [a0, b0, c0, d0] s1 = [a1, b1, c1, d1] s2 = [a2, b2, c2, d2] s3 = [a3, b3, c3, d3] s4 = [a4, b4, c4, d4] return invert_round1(s0, [s1, s2, s3, s4])
def assert_collidable_round1(words, extra=False): a0, b0, c0, d0 = md4.INITIAL_STATE states = md4.do_round1(words) a1, b1, c1, d1 = states[0] a2, b2, c2, d2 = states[1] a3, b3, c3, d3 = states[2] a4, b4, c4, d4 = states[3] assert_bit1(a1, 7, b0, 7) assert_bit1(d1, 7, 0) assert_bit1(d1, 8, a1, 8) assert_bit1(d1, 11, a1, 11) assert_bit1(c1, 7, 1) assert_bit1(c1, 8, 1) assert_bit1(c1, 11, 0) assert_bit1(c1, 26, d1, 26) assert_bit1(b1, 7, 1) assert_bit1(b1, 8, 0) assert_bit1(b1, 11, 0) assert_bit1(b1, 26, 0) if extra: # Still needed? assert_bit1(b1, 20, 0) assert_bit1(a2, 8, 1) assert_bit1(a2, 11, 1) assert_bit1(a2, 26, 0) assert_bit1(a2, 14, b1, 14) if extra: for i in [16, 17, 19, 22]: assert_bit(a2, i, nth_bit(b1, i)) assert_bit1(d2, 14, 0) assert_bit1(d2, 19, a2, 19) assert_bit1(d2, 20, a2, 20) assert_bit1(d2, 21, a2, 21) assert_bit1(d2, 22, a2, 22) assert_bit1(d2, 26, 1) if extra: for i in [16, 17, 19, 22]: assert_bit(d2, i, 0) assert_bit1(c2, 13, d2, 13) assert_bit1(c2, 14, 0) assert_bit1(c2, 15, d2, 15) assert_bit1(c2, 19, 0) assert_bit1(c2, 20, 0) assert_bit1(c2, 21, 1) assert_bit1(c2, 22, 0) if extra: for i in [16, 17, 19, 22]: assert_bit(c2, i, 0) assert_bit1(b2, 13, 1) assert_bit1(b2, 14, 1) assert_bit1(b2, 15, 0) assert_bit1(b2, 17, c2, 17) assert_bit1(b2, 19, 0) assert_bit1(b2, 20, 0) assert_bit1(b2, 21, 0) assert_bit1(b2, 22, 0) if extra: for i in [16, 17, 19, 22]: assert_bit(b2, i, 0) assert_bit1(a3, 13, 1) assert_bit1(a3, 14, 1) assert_bit1(a3, 15, 1) assert_bit1(a3, 17, 0) assert_bit1(a3, 19, 0) assert_bit1(a3, 20, 0) assert_bit1(a3, 21, 0) assert_bit1(a3, 23, b2, 23) assert_bit1(a3, 22, 1) assert_bit1(a3, 26, b2, 26) assert_bit1(d3, 13, 1) assert_bit1(d3, 14, 1) assert_bit1(d3, 15, 1) assert_bit1(d3, 17, 0) assert_bit1(d3, 20, 0) assert_bit1(d3, 21, 1) assert_bit1(d3, 22, 1) assert_bit1(d3, 23, 0) assert_bit1(d3, 26, 1) assert_bit1(d3, 30, a3, 30) assert_bit1(c3, 17, 1) assert_bit1(c3, 20, 0) assert_bit1(c3, 21, 0) assert_bit1(c3, 22, 0) assert_bit1(c3, 23, 0) assert_bit1(c3, 26, 0) assert_bit1(c3, 30, 1) assert_bit1(c3, 32, d3, 32) assert_bit1(b3, 20, 0) assert_bit1(b3, 21, 1) assert_bit1(b3, 22, 1) assert_bit1(b3, 23, c3, 23) assert_bit1(b3, 26, 1) assert_bit1(b3, 30, 0) assert_bit1(b3, 32, 0) assert_bit1(a4, 23, 0) assert_bit1(a4, 26, 0) assert_bit1(a4, 27, b3, 27) assert_bit1(a4, 29, b3, 29) assert_bit1(a4, 30, 1) assert_bit1(a4, 32, 0) assert_bit1(d4, 23, 0) assert_bit1(d4, 26, 0) assert_bit1(d4, 27, 1) assert_bit1(d4, 29, 1) assert_bit1(d4, 30, 0) assert_bit1(d4, 32, 1) assert_bit1(c4, 19, d4, 19) assert_bit1(c4, 23, 1) assert_bit1(c4, 26, 1) assert_bit1(c4, 27, 0) assert_bit1(c4, 29, 0) assert_bit1(c4, 30, 0) assert_bit1(b4, 19, 0) assert_bit1(b4, 26, 1) assert_bit1(b4, 27, 1) assert_bit1(b4, 29, 1) assert_bit1(b4, 30, 0) # From https://eprint.iacr.org/2005/151.pdf . assert_bit1(b4, 32, c4, 32)