code: def validate_update(filepath: str,
                      progress_callback: Callable[[float], None],
                      cert_path: Optional[str]):
      
  
      def zip_callback(progress):
          progress_callback(progress/2.0)
  
      required = [ROOTFS_NAME, ROOTFS_HASH_NAME]
      if cert_path:
          required.append(ROOTFS_SIG_NAME)
      files, sizes = unzip_update(filepath, zip_callback,
                                  UPDATE_FILES,
                                  required)
  
      def hash_callback(progress):
          progress_callback(progress/2.0 + 0.5)
      rootfs = files.get(ROOTFS_NAME)
      assert rootfs
      rootfs_hash = hash_file(rootfs,
                              hash_callback,
                              file_size=sizes[ROOTFS_NAME])
      hashfile = files.get(ROOTFS_HASH_NAME)
      assert hashfile
      packaged_hash = open(hashfile, 'rb').read().strip()
      if packaged_hash != rootfs_hash:
          msg = f"Hash mismatch: calculated {rootfs_hash} != "\
              f"packaged {packaged_hash}"
          LOG.error(msg)
          raise HashMismatch(msg)
  
      if cert_path:
          sigfile = files.get(ROOTFS_SIG_NAME)
          assert sigfile
          verify_signature(hashfile, sigfile, cert_path)
  
      return rootfs
docs: Worker for validation. Call in an executor (so it can return things)
  
      - Unzips filepath to its directory
      - Hashes the rootfs inside
      - If requested, checks the signature of the hash
      :param filepath: The path to the update zip file
      :param progress_callback: The function to call with progress between 0
                                and 1.0. May never reach precisely 1.0, best
                                only for user information
      :param cert_path: Path to an x.509 certificate to check the signature
                        against. If ``None``, signature checking is disabled
      :returns str: Path to the rootfs file to update
  
      Will also raise an exception if validation fails