Skip to content

Proof API Reference

The Proof module communicates with the local Proof Server to generate zero-knowledge proofs required for shielded transactions.

Proof Server Client

noxipher.proof.client.ProofServerClient

Async HTTP client for Proof Server.

Proof Server runs LOCAL (private data never leaves user's machine). Or use hosted: lace-proof-pub..midnight.network

Source code in src/noxipher/proof/client.py
class ProofServerClient:
    """
    Async HTTP client for Proof Server.

    Proof Server runs LOCAL (private data never leaves user's machine).
    Or use hosted: lace-proof-pub.<network>.midnight.network
    """

    def __init__(self, proof_server_url: str, timeout: float = 300.0) -> None:
        # ZK proof generation can take several minutes
        self._url = proof_server_url.rstrip("/")
        self._timeout = timeout
        self._client: httpx.AsyncClient | None = None

    async def __aenter__(self) -> ProofServerClient:
        self._client = httpx.AsyncClient(timeout=self._timeout)
        return self

    async def __aexit__(self, *args: object) -> None:
        if self._client:
            await self._client.aclose()

    async def health(self) -> dict[str, Any]:
        """
        GET /health → {"status": "ok", "version": "8.0.3", ...}

        Verify proof server is running and version is correct.
        """
        assert self._client is not None
        try:
            resp = await self._client.get(f"{self._url}/health")
            resp.raise_for_status()
            return cast(dict[str, Any], resp.json())
        except httpx.HTTPError as e:
            raise ProofError(f"Proof server health check failed: {e}") from e

    @retry(stop=stop_after_attempt(2), wait=wait_exponential(min=2, max=30))
    async def prove(
        self,
        circuit_id: str,
        proving_key: bytes,
        private_inputs: dict[str, Any],
        public_inputs: dict[str, Any],
    ) -> bytes:
        """
        POST /prove → ZK proof bytes.
        """
        assert self._client is not None
        # Format for Proof Server v8.0.3 (confirmed snake_case)
        payload = {
            "circuit_id": circuit_id,
            "proving_key": proving_key.hex(),
            "private_inputs": private_inputs,
            "public_inputs": public_inputs,
        }
        try:
            resp = await self._client.post(f"{self._url}/prove", json=payload)
            resp.raise_for_status()
            return resp.content
        except httpx.HTTPError as e:
            raise ProofError(f"Proof generation failed: {e}") from e

    async def get_proving_key(self, circuit_id: str) -> bytes:
        """GET /keys/{circuit_id} → Proving key bytes."""
        assert self._client is not None
        try:
            resp = await self._client.get(f"{self._url}/keys/{circuit_id}")
            resp.raise_for_status()
            return resp.content
        except httpx.HTTPError as e:
            raise ProofError(f"Failed to get proving key for {circuit_id}: {e}") from e

get_proving_key(circuit_id) async

GET /keys/{circuit_id} → Proving key bytes.

Source code in src/noxipher/proof/client.py
async def get_proving_key(self, circuit_id: str) -> bytes:
    """GET /keys/{circuit_id} → Proving key bytes."""
    assert self._client is not None
    try:
        resp = await self._client.get(f"{self._url}/keys/{circuit_id}")
        resp.raise_for_status()
        return resp.content
    except httpx.HTTPError as e:
        raise ProofError(f"Failed to get proving key for {circuit_id}: {e}") from e

health() async

GET /health → {"status": "ok", "version": "8.0.3", ...}

Verify proof server is running and version is correct.

Source code in src/noxipher/proof/client.py
async def health(self) -> dict[str, Any]:
    """
    GET /health → {"status": "ok", "version": "8.0.3", ...}

    Verify proof server is running and version is correct.
    """
    assert self._client is not None
    try:
        resp = await self._client.get(f"{self._url}/health")
        resp.raise_for_status()
        return cast(dict[str, Any], resp.json())
    except httpx.HTTPError as e:
        raise ProofError(f"Proof server health check failed: {e}") from e

prove(circuit_id, proving_key, private_inputs, public_inputs) async

POST /prove → ZK proof bytes.

Source code in src/noxipher/proof/client.py
@retry(stop=stop_after_attempt(2), wait=wait_exponential(min=2, max=30))
async def prove(
    self,
    circuit_id: str,
    proving_key: bytes,
    private_inputs: dict[str, Any],
    public_inputs: dict[str, Any],
) -> bytes:
    """
    POST /prove → ZK proof bytes.
    """
    assert self._client is not None
    # Format for Proof Server v8.0.3 (confirmed snake_case)
    payload = {
        "circuit_id": circuit_id,
        "proving_key": proving_key.hex(),
        "private_inputs": private_inputs,
        "public_inputs": public_inputs,
    }
    try:
        resp = await self._client.post(f"{self._url}/prove", json=payload)
        resp.raise_for_status()
        return resp.content
    except httpx.HTTPError as e:
        raise ProofError(f"Proof generation failed: {e}") from e