Protocol Concepts
ZAP Source

ZAP Source

Need to build a ZAP Source? Check out the ZAP Source Guide!

Currently, HTTP requests inside a proof is NOT-SUPPORTED by Mina.

We need a workaround: The ZAP Sources! They are a subset of the possible sources that can be used during the off-chain proof generation. Source only refers to the HTTP endpoints used to fetch the data.

Zap Sources are web2 API. They expose endpoints that wraps specific HTTP requests and gets the result on behalf of the user. The response is signed with a pair of keys.

This allow the user to make the HTTP request in an unsafe environment (outside of the proof) and use the response inside the proof. During the verification, the ZAP Source public key is used to verify the signature of the response, thus emulating an HTTP request inside a proof.

Following the loan example, a Bank ZAP Source is deployed. The user makes a HTTP request to this source with his bank authentification token. The ZAP source relays the request to the bank, and send back the response signed with its private key. The user generate a proof that he has more than a specific amount on his bank account using the value returned by the source, and the proof is verified on-chain against the source public key.

This is the only part where there is a privacy issue: The ZAP Source can see the user's bank account balance and authentification token. We are researching a solution to this problem and open to suggestions/ideas!

Interface of a ZAP Source

Each request body must be of type ZapRequestParams and contain the mina_address of the user that made the request:

export type ZapRequestParams = {
  mina_address: string;
  args?: {
    [key: string]: any;
  };
};

The args object contains the arguments of the request. The args object is optional and can be omitted if the endpoint doesn't require any arguments. The path of the request correspond to the full path of the endpoint, for example /api/example/number.

The args and path are used to sign the response with the source private key and ensure that the response is not tampered. This can be represented as an object of type Route:

export type Route = {
  path: string;
  args?: {
    [key: string]: any;
  };
};

The returned value must be of type SupportedTargetValue (currently, only number is supported), which is the data returned by the endpoint and that will be used inside the attestation and verified in the ZAP contract. But this value must be wrapped in an object of type ZapSignedResponse with a signature of the response data with the source private key and the hashRoute.

That way, for a given Route, value and signature, we can verify that the value comes from the oracle of public key P by computing hash(Route.path, Route.args) and checking that signature == sign({value, hash(Route.path, Route.args)}, P).

The definitive response is of type ZapSignedResponse:

type ZapSignedResponse = {
    data: {
      value: number;
      hashRoute: hash(Route.path, Route.args);
    };
    signature: string;
    publicKey: string;
}

The express.js zapMiddleware of the source template can be used to automatically wrap SupportedTargetValue responses in a ZapSignedResponse object. Follow the ZAP Source Guide for more information.