ZiskStream
ZiskStream is the streaming counterpart to ZiskStdin. Instead of
holding the entire input in memory before proving, it is backed by a
live transport and pushes data to the prover as it becomes available.
Overview
ZiskStream mirrors the ZiskStdin write API but pushes bytes over
a live transport instead of buffering everything in memory. Use it
for inputs too large to materialize up front, or to feed the prover
incrementally and reduce latency. It implements both
Into<InputSource> (interchangeable with ZiskStdin in prove /
execute) and Into<HintsSource>. Writes accumulate locally; the
first flush() opens the transport and pushes pending bytes; the
SDK calls finish() when the JobHandle resolves, after which the
stream is reusable for the next job.
Type
pub struct ZiskStream { /* private */ }
Constructors
ZiskStream is created through one of five transport constructors,
each suited to a different deployment.
unix
Open a Unix domain socket at an auto-assigned /tmp/ path.
pub fn unix() -> ZiskStream
Use this when the host and prover run on the same machine and you do not care about the socket location.
Example
use zisk_sdk::ZiskStream;
let stream = ZiskStream::unix();
println!("listening on {}", stream.uri());
// e.g. "unix:///tmp/zisk-input-3a7f.sock"
unix_external
Attach to a Unix domain socket that another process has already bound and is listening on. The SDK only writes through the existing socket; it does not create, bind, or unlink it.
pub fn unix_external(path: &str) -> ZiskStream
Parameters
| Name | Type | Description |
|---|---|---|
path | &str | Filesystem path of an existing, externally-managed socket. |
Use this when a sidecar or supervising process owns the socket lifecycle and your client only needs to write to it.
unix_at
Create and bind a new Unix domain socket at an explicit path. The SDK owns the socket.
pub fn unix_at(path: &str) -> Result<ZiskStream>
Parameters
| Name | Type | Description |
|---|---|---|
path | &str | Filesystem path where the socket will be created. |
Use this when you need to control the socket location. The socket starts listening immediately so the executor can connect as soon as it launches.
quic
Open a QUIC-over-UDP transport.
pub fn quic(uri: &str) -> Result<ZiskStream>
Parameters
| Name | Type | Description |
|---|---|---|
uri | &str | A quic://host:port URI. Pass :0 to let the OS pick a port. |
Use this when host and prover run on different machines and you want a direct point-to-point transport.
Example
let stream = ZiskStream::quic("quic://127.0.0.1:0")?;
grpc
Open a gRPC push transport. Frames are pushed to the coordinator via
the PushJobInput RPC.
pub fn grpc() -> ZiskStream
Use this in cluster and remote-prover deployments where the coordinator drives the connection between host and prover.
Write methods
write
Bincode-serialize a typed value and buffer it as one framed record:
a u64 length header followed by the serialized payload, zero-padded
to the next 8-byte boundary.
pub fn write<T: Serialize>(&self, data: &T)
The guest reads this record with io::read::<T>(), which consumes
the header, the payload, and the trailing padding in one step.
write_slice
Buffer raw bytes as one framed record. Same framing as write (a
u64 length header followed by the bytes, zero-padded to the next
8-byte boundary), but the payload is written verbatim instead of
going through bincode.
pub fn write_slice(&self, data: &[u8])
The guest reads the record with io::read_slice(&mut buf), which
consumes the header, the payload, and the trailing padding. Use this
when the data is already in byte form.
write_bytes
Buffer raw bytes with no framing, no length header, no padding, no record boundary. The bytes are appended to the transport stream exactly as supplied.
pub fn write_bytes(&self, data: &[u8])
Useful when the guest performs a read_bytes whose size it already
knows from another channel (e.g. derived from a separately-read
count). Without a length prefix the guest is responsible for knowing
how many bytes to consume.
Lifecycle methods
flush
Send every buffered byte over the transport. Blocks until the prover
is connected; the first flush() after construction (or after a
finish()) opens the transport implicitly.
pub fn flush(&self) -> Result<()>
Example
let stream = ZiskStream::unix();
stream.write(&3u64); // buffered locally
stream.flush()?; // opens transport, sends the record
stream.write(&"hi".to_string());
stream.flush()?; // reuses the open transport
reset
Discard buffered bytes that have not yet been sent. Bytes already flushed cannot be taken back.
pub fn reset(&self)
finish
Close the current transport and mark the stream as not-live. The SDK
calls finish automatically when the JobHandle is awaited, so most
callers do not need to invoke it directly.
pub fn finish(&self) -> Result<()>
Any flush() issued after finish() blocks until the next call
re-opens the transport preventing accidental writes to a completed
job.
Accessors
uri
Return the transport URI for the current stream.
pub fn uri(&self) -> &str
Useful for logging, or for handing the URI to a separate process that will connect on the other side of the transport.
Example of usage
ZiskStream is interchangeable with ZiskStdin at the call site:
use zisk_sdk::{GuestProgram, ProverClient, ZiskStream, load_program};
static PROGRAM: GuestProgram = load_program!(
"target/riscv64ima-zisk-zkvm-elf/release/my-guest"
);
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = ProverClient::embedded().build()?;
client.setup(&PROGRAM).run()?.await?;
let stream = ZiskStream::unix();
stream.write(&3u64);
// Submit before the rest of the input has been produced
let job = client.prove(&PROGRAM, stream.clone()).run()?;
// Push records in as they arrive — the prover blocks on each
// read until the next flush lands
for chunk in producer.chunks() {
stream.write_slice(&chunk);
stream.flush()?;
}
let proof = job.await?;
Ok(())
}
The byte contract with the guest does not change — the host still has to write values in the order the guest reads them. Only when the bytes arrive differs. From the guest's perspective there is no difference between buffered and streamed input.