def get_discriminant(challenge, size_bites): if (challenge, size_bites) in discriminant_cache: return discriminant_cache[(challenge, size_bites)] else: dsc = int( create_discriminant(challenge, size_bites), 16, ) add_to_cache((challenge, size_bites), dsc) return dsc
def test_prove_and_verify(): discriminant_challenge = secrets.token_bytes(10) discriminant_size = 512 discriminant = create_discriminant(discriminant_challenge, discriminant_size) int_size = (discriminant_size + 16) >> 4 iters = 1000000 t1 = time.time() result = prove(discriminant_challenge, discriminant_size, iters) t2 = time.time() print(f"IPS: {iters / (t2 - t1)}") is_valid = verify_wesolowski( str(discriminant), str(2), str(1), str( int.from_bytes( result[0:int_size], "big", signed=True, ) ), str( int.from_bytes( result[int_size:2 * int_size], "big", signed=True, ) ), str( int.from_bytes( result[2 * int_size:3 * int_size], "big", signed=True, ) ), str( int.from_bytes( result[3 * int_size:4 * int_size], "big", signed=True, ) ), iters, ) assert is_valid
def test_prove_and_verify(): discriminant_challenge = secrets.token_bytes(10) discriminant_size = 512 discriminant = create_discriminant(discriminant_challenge, discriminant_size) form_size = 100 initial_el = b"\x08" + (b"\x00" * 99) iters = 1000000 t1 = time.time() result = prove(discriminant_challenge, initial_el, discriminant_size, iters) t2 = time.time() print(f"IPS: {iters / (t2 - t1)}") result_y = result[:form_size] proof = result[form_size:2 * form_size] is_valid = verify_wesolowski( str(discriminant), initial_el, result_y, proof, iters, ) assert is_valid # Creates another proof starting at the previous output iters_2 = 200000 t1 = time.time() result_2 = prove( discriminant_challenge, result_y, discriminant_size, iters_2, ) t2 = time.time() print(f"IPS: {iters_2 / (t2 - t1)}") is_valid = verify_wesolowski( str(discriminant), result_y, result_2[:form_size], result_2[form_size:2 * form_size], iters_2, ) assert is_valid
def is_valid(self, discriminant_size_bits): try: disc: int = int( create_discriminant(self.challenge_hash, discriminant_size_bits), 16, ) x = ClassGroup.from_ab_discriminant(2, 1, disc) y = ClassGroup.from_ab_discriminant(self.output.a, self.output.b, disc) except Exception: return False return check_proof_of_time_nwesolowski( disc, x, y.serialize() + bytes(self.witness), self.number_of_iterations, discriminant_size_bits, self.witness_type, )
def get_discriminant(challenge, size_bites) -> int: return int( create_discriminant(challenge, size_bites), 16, )
async def _do_process_communication( self, chain: Chain, challenge: bytes32, initial_form: ClassgroupElement, ip: str, reader: asyncio.StreamReader, writer: asyncio.StreamWriter, ): disc: int = create_discriminant(challenge, self.constants.DISCRIMINANT_SIZE_BITS) try: # Depending on the flags 'fast_algorithm' and 'sanitizer_mode', # the timelord tells the vdf_client what to execute. async with self.lock: if self.config["fast_algorithm"]: # Run n-wesolowski (fast) algorithm. writer.write(b"N") else: # Run two-wesolowski (slow) algorithm. writer.write(b"T") await writer.drain() prefix = str(len(str(disc))) if len(prefix) == 1: prefix = "00" + prefix if len(prefix) == 2: prefix = "0" + prefix async with self.lock: writer.write((prefix + str(disc)).encode()) await writer.drain() # Send initial_form prefixed with its length. async with self.lock: writer.write(bytes([len(initial_form.data)]) + initial_form.data) await writer.drain() try: ok = await reader.readexactly(2) except (asyncio.IncompleteReadError, ConnectionResetError, Exception) as e: log.warning(f"{type(e)} {e}") async with self.lock: self.vdf_failures.append(chain) self.vdf_failures_count += 1 return if ok.decode() != "OK": return log.info("Got handshake with VDF client.") async with self.lock: self.allows_iters.append(chain) # Listen to the client until "STOP" is received. while True: try: data = await reader.readexactly(4) except ( asyncio.IncompleteReadError, ConnectionResetError, Exception, ) as e: log.warning(f"{type(e)} {e}") async with self.lock: self.vdf_failures.append(chain) self.vdf_failures_count += 1 break msg = "" try: msg = data.decode() except Exception: pass if msg == "STOP": log.info(f"Stopped client running on ip {ip}.") async with self.lock: writer.write(b"ACK") await writer.drain() break else: try: # This must be a proof, 4 bytes is length prefix length = int.from_bytes(data, "big") proof = await reader.readexactly(length) stdout_bytes_io: io.BytesIO = io.BytesIO(bytes.fromhex(proof.decode())) except ( asyncio.IncompleteReadError, ConnectionResetError, Exception, ) as e: log.warning(f"{type(e)} {e}") async with self.lock: self.vdf_failures.append(chain) self.vdf_failures_count += 1 break iterations_needed = uint64(int.from_bytes(stdout_bytes_io.read(8), "big", signed=True)) y_size_bytes = stdout_bytes_io.read(8) y_size = uint64(int.from_bytes(y_size_bytes, "big", signed=True)) y_bytes = stdout_bytes_io.read(y_size) witness_type = uint8(int.from_bytes(stdout_bytes_io.read(1), "big", signed=True)) proof_bytes: bytes = stdout_bytes_io.read() # Verifies our own proof just in case form_size = ClassgroupElement.get_size(self.constants) output = ClassgroupElement.from_bytes(y_bytes[:form_size]) time_taken = time.time() - self.chain_start_time[chain] ips = int(iterations_needed / time_taken * 10) / 10 log.info( f"Finished PoT chall:{challenge[:10].hex()}.. {iterations_needed}" f" iters, " f"Estimated IPS: {ips}, Chain: {chain}" ) vdf_info: VDFInfo = VDFInfo( challenge, iterations_needed, output, ) vdf_proof: VDFProof = VDFProof( witness_type, proof_bytes, ) if not vdf_proof.is_valid(self.constants, initial_form, vdf_info): log.error("Invalid proof of time!") async with self.lock: self.proofs_finished.append((chain, vdf_info, vdf_proof)) except ConnectionResetError as e: log.info(f"Connection reset with VDF client {e}")
async def _do_process_communication( self, chain: Chain, challenge: bytes32, initial_form: ClassgroupElement, ip: str, reader: asyncio.StreamReader, writer: asyncio.StreamWriter, # Data specific only when running in bluebox mode. bluebox_iteration: Optional[uint64] = None, header_hash: Optional[bytes32] = None, height: Optional[uint32] = None, field_vdf: Optional[uint8] = None, # Labels a proof to the current state only proof_label: Optional[int] = None, ): disc: int = create_discriminant(challenge, self.constants.DISCRIMINANT_SIZE_BITS) try: # Depending on the flags 'fast_algorithm' and 'sanitizer_mode', # the timelord tells the vdf_client what to execute. async with self.lock: if self.sanitizer_mode: writer.write(b"S") else: if self.config["fast_algorithm"]: # Run n-wesolowski (fast) algorithm. writer.write(b"N") else: # Run two-wesolowski (slow) algorithm. writer.write(b"T") await writer.drain() prefix = str(len(str(disc))) if len(prefix) == 1: prefix = "00" + prefix if len(prefix) == 2: prefix = "0" + prefix async with self.lock: writer.write((prefix + str(disc)).encode()) await writer.drain() # Send initial_form prefixed with its length. async with self.lock: writer.write(bytes([len(initial_form.data)]) + initial_form.data) await writer.drain() try: ok = await reader.readexactly(2) except (asyncio.IncompleteReadError, ConnectionResetError, Exception) as e: log.warning(f"{type(e)} {e}") async with self.lock: self.vdf_failures.append((chain, proof_label)) self.vdf_failures_count += 1 return None if ok.decode() != "OK": return None log.debug("Got handshake with VDF client.") if not self.sanitizer_mode: async with self.lock: self.allows_iters.append(chain) else: async with self.lock: assert chain is Chain.BLUEBOX assert bluebox_iteration is not None prefix = str(len(str(bluebox_iteration))) if len(str(bluebox_iteration)) < 10: prefix = "0" + prefix iter_str = prefix + str(bluebox_iteration) writer.write(iter_str.encode()) await writer.drain() # Listen to the client until "STOP" is received. while True: try: data = await reader.readexactly(4) except ( asyncio.IncompleteReadError, ConnectionResetError, Exception, ) as e: log.warning(f"{type(e)} {e}") async with self.lock: self.vdf_failures.append((chain, proof_label)) self.vdf_failures_count += 1 break msg = "" try: msg = data.decode() except Exception: pass if msg == "STOP": log.debug(f"Stopped client running on ip {ip}.") async with self.lock: writer.write(b"ACK") await writer.drain() break else: try: # This must be a proof, 4 bytes is length prefix length = int.from_bytes(data, "big") proof = await reader.readexactly(length) stdout_bytes_io: io.BytesIO = io.BytesIO(bytes.fromhex(proof.decode())) except ( asyncio.IncompleteReadError, ConnectionResetError, Exception, ) as e: log.warning(f"{type(e)} {e}") async with self.lock: self.vdf_failures.append((chain, proof_label)) self.vdf_failures_count += 1 break iterations_needed = uint64(int.from_bytes(stdout_bytes_io.read(8), "big", signed=True)) y_size_bytes = stdout_bytes_io.read(8) y_size = uint64(int.from_bytes(y_size_bytes, "big", signed=True)) y_bytes = stdout_bytes_io.read(y_size) witness_type = uint8(int.from_bytes(stdout_bytes_io.read(1), "big", signed=True)) proof_bytes: bytes = stdout_bytes_io.read() # Verifies our own proof just in case form_size = ClassgroupElement.get_size(self.constants) output = ClassgroupElement.from_bytes(y_bytes[:form_size]) if not self.sanitizer_mode: time_taken = time.time() - self.chain_start_time[chain] ips = int(iterations_needed / time_taken * 10) / 10 log.info( f"Finished PoT chall:{challenge[:10].hex()}.. {iterations_needed}" f" iters, " f"Estimated IPS: {ips}, Chain: {chain}" ) vdf_info: VDFInfo = VDFInfo( challenge, iterations_needed, output, ) vdf_proof: VDFProof = VDFProof( witness_type, proof_bytes, self.sanitizer_mode, ) if not vdf_proof.is_valid(self.constants, initial_form, vdf_info): log.error("Invalid proof of time!") if not self.sanitizer_mode: async with self.lock: assert proof_label is not None self.proofs_finished.append((chain, vdf_info, vdf_proof, proof_label)) else: async with self.lock: writer.write(b"010") await writer.drain() assert header_hash is not None assert field_vdf is not None assert height is not None response = timelord_protocol.RespondCompactProofOfTime( vdf_info, vdf_proof, header_hash, height, field_vdf ) if self.server is not None: message = make_msg(ProtocolMessageTypes.respond_compact_proof_of_time, response) await self.server.send_to_all([message], NodeType.FULL_NODE) except ConnectionResetError as e: log.debug(f"Connection reset with VDF client {e}")
async def _do_process_communication(self, challenge_hash, challenge_weight, ip, reader, writer): disc: int = create_discriminant( challenge_hash, self.constants["DISCRIMINANT_SIZE_BITS"]) prefix = str(len(str(disc))) if len(prefix) == 1: prefix = "00" + prefix writer.write((prefix + str(disc)).encode()) await writer.drain() try: ok = await reader.readexactly(2) except (asyncio.IncompleteReadError, ConnectionResetError, Exception) as e: log.warning(f"{type(e)} {e}") async with self.lock: if challenge_hash not in self.done_discriminants: self.done_discriminants.append(challenge_hash) return if ok.decode() != "OK": return log.info("Got handshake with VDF client.") async with self.lock: self.active_discriminants[challenge_hash] = (writer, challenge_weight, ip) self.active_discriminants_start_time[challenge_hash] = time.time() asyncio.create_task(self._send_iterations(challenge_hash, writer)) # Listen to the client until "STOP" is received. while True: try: data = await reader.readexactly(4) except (asyncio.IncompleteReadError, ConnectionResetError, Exception) as e: log.warning(f"{type(e)} {e}") async with self.lock: if challenge_hash in self.active_discriminants: del self.active_discriminants[challenge_hash] if challenge_hash in self.active_discriminants_start_time: del self.active_discriminants_start_time[ challenge_hash] if challenge_hash not in self.done_discriminants: self.done_discriminants.append(challenge_hash) break msg = "" try: msg = data.decode() except Exception as e: log.error(f"Exception while decoding data {e}") pass if msg == "STOP": log.info(f"Stopped client running on ip {ip}.") async with self.lock: writer.write(b"ACK") await writer.drain() break else: try: # This must be a proof, 4bytes is length prefix length = int.from_bytes(data, "big") proof = await reader.readexactly(length) stdout_bytes_io: io.BytesIO = io.BytesIO( bytes.fromhex(proof.decode())) except ( asyncio.IncompleteReadError, ConnectionResetError, Exception, ) as e: log.warning(f"{type(e)} {e}") async with self.lock: if challenge_hash in self.active_discriminants: del self.active_discriminants[challenge_hash] if challenge_hash in self.active_discriminants_start_time: del self.active_discriminants_start_time[ challenge_hash] if challenge_hash not in self.done_discriminants: self.done_discriminants.append(challenge_hash) break iterations_needed = uint64( int.from_bytes(stdout_bytes_io.read(8), "big", signed=True)) y_size_bytes = stdout_bytes_io.read(8) y_size = uint64( int.from_bytes(y_size_bytes, "big", signed=True)) y_bytes = stdout_bytes_io.read(y_size) proof_bytes: bytes = stdout_bytes_io.read() # Verifies our own proof just in case a = int.from_bytes(y_bytes[:129], "big", signed=True) b = int.from_bytes(y_bytes[129:], "big", signed=True) output = ClassgroupElement(int512(a), int512(b)) proof_of_time = ProofOfTime( challenge_hash, iterations_needed, output, self.config["n_wesolowski"], proof_bytes, ) if not proof_of_time.is_valid( self.constants["DISCRIMINANT_SIZE_BITS"]): log.error("Invalid proof of time") response = timelord_protocol.ProofOfTimeFinished(proof_of_time) await self._update_avg_ips(challenge_hash, iterations_needed, ip) async with self.lock: self.proofs_to_write.append( OutboundMessage( NodeType.FULL_NODE, Message("proof_of_time_finished", response), Delivery.BROADCAST, )) await self._update_proofs_count(challenge_weight)
async def _do_process_communication( self, challenge_hash, challenge_weight, ip, reader, writer ): disc: int = create_discriminant(challenge_hash, self.discriminant_size_bits) # Depending on the flags 'fast_algorithm' and 'sanitizer_mode', # the timelord tells the vdf_client what to execute. if not self.sanitizer_mode: if self.config["fast_algorithm"]: # Run n-wesolowski (fast) algorithm. writer.write(b"N") else: # Run two-wesolowski (slow) algorithm. writer.write(b"T") else: # Create compact proofs of time. writer.write(b"S") await writer.drain() prefix = str(len(str(disc))) if len(prefix) == 1: prefix = "00" + prefix writer.write((prefix + str(disc)).encode()) await writer.drain() try: ok = await reader.readexactly(2) except (asyncio.IncompleteReadError, ConnectionResetError, Exception) as e: log.warning(f"{type(e)} {e}") async with self.lock: if challenge_hash not in self.done_discriminants: self.done_discriminants.append(challenge_hash) if self.sanitizer_mode: if challenge_hash in self.pending_iters: del self.pending_iters[challenge_hash] if challenge_hash in self.submitted_iters: del self.submitted_iters[challenge_hash] return if ok.decode() != "OK": return log.info("Got handshake with VDF client.") async with self.lock: self.active_discriminants[challenge_hash] = (writer, challenge_weight, ip) self.active_discriminants_start_time[challenge_hash] = time.time() asyncio.create_task(self._send_iterations(challenge_hash, writer)) # Listen to the client until "STOP" is received. while True: try: data = await reader.readexactly(4) except (asyncio.IncompleteReadError, ConnectionResetError, Exception) as e: log.warning(f"{type(e)} {e}") async with self.lock: if challenge_hash in self.active_discriminants: del self.active_discriminants[challenge_hash] if challenge_hash in self.active_discriminants_start_time: del self.active_discriminants_start_time[challenge_hash] if challenge_hash not in self.done_discriminants: self.done_discriminants.append(challenge_hash) if self.sanitizer_mode: if challenge_hash in self.pending_iters: del self.pending_iters[challenge_hash] if challenge_hash in self.submitted_iters: del self.submitted_iters[challenge_hash] break msg = "" try: msg = data.decode() except Exception as e: log.error(f"Exception while decoding data {e}") if msg == "STOP": log.info(f"Stopped client running on ip {ip}.") async with self.lock: writer.write(b"ACK") await writer.drain() break else: try: # This must be a proof, 4bytes is length prefix length = int.from_bytes(data, "big") proof = await reader.readexactly(length) stdout_bytes_io: io.BytesIO = io.BytesIO( bytes.fromhex(proof.decode()) ) except ( asyncio.IncompleteReadError, ConnectionResetError, Exception, ) as e: log.warning(f"{type(e)} {e}") async with self.lock: if challenge_hash in self.active_discriminants: del self.active_discriminants[challenge_hash] if challenge_hash in self.active_discriminants_start_time: del self.active_discriminants_start_time[challenge_hash] if challenge_hash not in self.done_discriminants: self.done_discriminants.append(challenge_hash) if self.sanitizer_mode: if challenge_hash in self.pending_iters: del self.pending_iters[challenge_hash] if challenge_hash in self.submitted_iters: del self.submitted_iters[challenge_hash] break iterations_needed = uint64( int.from_bytes(stdout_bytes_io.read(8), "big", signed=True) ) y_size_bytes = stdout_bytes_io.read(8) y_size = uint64(int.from_bytes(y_size_bytes, "big", signed=True)) y_bytes = stdout_bytes_io.read(y_size) witness_type = uint8( int.from_bytes(stdout_bytes_io.read(1), "big", signed=True) ) proof_bytes: bytes = stdout_bytes_io.read() # Verifies our own proof just in case a = int.from_bytes(y_bytes[:129], "big", signed=True) b = int.from_bytes(y_bytes[129:], "big", signed=True) output = ClassgroupElement(int512(a), int512(b)) proof_of_time = ProofOfTime( challenge_hash, iterations_needed, output, witness_type, proof_bytes, ) if not proof_of_time.is_valid(self.discriminant_size_bits): log.error("Invalid proof of time") response = timelord_protocol.ProofOfTimeFinished(proof_of_time) await self._update_avg_ips(challenge_hash, iterations_needed, ip) async with self.lock: self.proofs_to_write.append( OutboundMessage( NodeType.FULL_NODE, Message("proof_of_time_finished", response), Delivery.BROADCAST, ) ) if not self.sanitizer_mode: await self._update_proofs_count(challenge_weight) else: async with self.lock: writer.write(b"010") await writer.drain() try: del self.active_discriminants[challenge_hash] del self.active_discriminants_start_time[challenge_hash] del self.pending_iters[challenge_hash] del self.submitted_iters[challenge_hash] except KeyError: log.error("Discriminant stopped anormally.")