def validate_breaks(otp, rounds):
	for (roundnum, source) in otp.breaks:
		result = cotpmd5.otpmd5_chain(source, rounds)
		print("{0:s} + {1:-6d} = {2:s} : {3:s}".format(otpmd5.tohex(source), 65535-roundnum, otpmd5.tohex(result[65535-roundnum]), otpmd5.tohex(otp.otp)))
		if otp.otp in result:
			print("Break found for {0:s}: {1:s}".format(repr(otp), otpmd5.tohex(source)))
			return True
	return False
	def save(self):
		filename = "otpmd5_{0:s}_{1:d}_{2:s}_candidates".format(self.seed, self.sequence, self.password)
		with open(filename, "w") as fd:
			for rounds, source in self.breaks:
				fd.write(str(rounds) + "\t" + otpmd5.tohex(source) + "\n")
def find_breaks(db, rounds, otp):
	print("Finding breaks for " + repr(otp))

	for (roundnum, value) in enumerate(cotpmd5.otpmd5_chain(otp.otp, rounds)):
		cur = db.cursor()
		cur.execute("SELECT source FROM otpmd5 WHERE result = %s", [int(numpy.int64(value))])
		for row in cur:
			source = numpy.uint64(row[0])
			otp.breaks.append((roundnum, source))
			print("Found candidate: {0:s}, roundnum={1:d}, source={2:s}, break={3:s}".format(repr(otp), roundnum, otpmd5.tohex(source), otpmd5.tohex(value)))
			sec_cur = db.cursor()
			sec_cur.execute("SELECT source FROM otpmd5_conflicts WHERE result = %s", [int(numpy.int64(value))])
			for row in sec_cur:
				source = numpy.uint64(row[0])
				otp.breaks.append((roundnum, source))
				print("Found candidate: {0:s}, roundnum={1:d}, source={2:s}, break={3:s}".format(repr(otp), roundnum, otpmd5.tohex(source), otpmd5.tohex(value)))
	def __repr__(self):
		return "random_otp(seed={0:s}, seq={1:d}, pass={2:s}, otp={3:s})".format(self.seed, self.sequence, self.password, otpmd5.tohex(self.otp))