Skip to main content

Deferred Computation

Let Fp\mathbb{F}_p and Fq\mathbb{F}_q be the two fields, with ∣Ep(Fq)∣=p|\mathbb{E}_p(\mathbb{F}_q)| = p, ∣Eq(Fp)∣=q|\mathbb{E}_q(\mathbb{F}_p)| = q for Elliptic curves Ep(Fq)\mathbb{E}_p(\mathbb{F}_q) and Eq(Fp)\mathbb{E}_q(\mathbb{F}_p). Assume q>pq > p. We have a proof system (Kimchi) over Fp\mathbb{F}_p and Fq\mathbb{F}_q, where commitments to public inputs are:

Pp=⟨e⃗,H⃗⟩∈Ep(Fq)Pq=⟨e⃗,G⃗⟩∈Eq(Fp)P_p = \langle \vec{e}, \vec{H} \rangle \in \mathbb{E}_p(\mathbb{F}_q) \\ P_q = \langle \vec{e}, \vec{G} \rangle \in \mathbb{E}_q(\mathbb{F}_p)

Respectively. See Pasta Curves for more details.

When referring to the Fq\mathbb{F}_q-side we mean the proof system for circuit over the field Fq\mathbb{F}_q.

Public Inputs / Why Passing​

In pickles-rs we have the notion of "passing" a variable (including the transcript) from one side to the other. e.g. when a field element α∈Fp\alpha \in \mathbb{F}_p needs to be used as a scalar on Fq\mathbb{F}_q.

This document explains what goes on "under the hood". Let us start by understanding why:

Let v∈Fqv \in \mathbb{F}_q be a scalar which we want to use to do both:

  1. Field arithmetic in Fq\mathbb{F}_q
  2. Scalar operations on Eq(Fp)\mathbb{E}_q(\mathbb{F}_p)

In order to do so efficiently, we need to split these operations across two circuits (and therefore proofs) because:

  1. Emulating Fq\mathbb{F}_q arithmetic in Fp\mathbb{F}_p is very expensive, e.g. computing v⋅wv \cdot w requires O(log⁡(q)2)O(\log(q)^2) multiplications over Fp\mathbb{F}_p: 100's of gates for a single multiplication.
  2. Since Eq(Fp)⊆Fp×Fp\mathbb{E}_q(\mathbb{F}_p) \subseteq \mathbb{F}_p \times \mathbb{F}_p we cannot compute [v]⋅H∈Eq(Fp)[v] \cdot H \in \mathbb{E}_q(\mathbb{F}_p) over Fq\mathbb{F}_q efficiently, because, like before, emulating Fp\mathbb{F}_p arithmetic in Fq\mathbb{F}_q is very expensive...

Solution​

The solution is to "pass" a value vv between the two proofs, in other words to have two values v~∈Fp\tilde{v} \in \mathbb{F}_p and v∈Fqv \in \mathbb{F}_q which are equal as integers i.e. lift(v)=lift(v~)∈Z\text{lift}(v) = \text{lift}(\tilde{v}) \in \mathbb{Z}: they represent "the same number". A naive first attempt would be to simply add v~∈Fp\tilde{v} \in \mathbb{F}_p to the witness on the Fp\mathbb{F}_p-side, however this has two problems:

Insufficient Field Size: p<qp < q hence vv cannot fit in Fp\mathbb{F}_p.

No Binding: More concerning, there is no binding between the v~\tilde{v} in the Fp\mathbb{F}_p-witness and the vv in the Fq\mathbb{F}_q-witness: a malicious prover could choose completely unrelated values. This violates soundness of the overall Fq/Fq\mathbb{F}_q/\mathbb{F}_q-relation being proved.

Problem 1: Decompose​

The solution to the first problem is simple:

In the Fq\mathbb{F}_q-side decompose v=2⋅h+lv = 2 \cdot h + l with h∈[0,2⌊log⁡p⌋)h \in [0, 2^{\lfloor \log p \rfloor}) (high bits) and l∈{0,1}l \in \{ 0, 1 \} (low bit). Note l,h<pl, h < p since 2p>q2 p > q; always the case for any cycle of curves, pp is only ≈q\approx \sqrt{q} smaller than qq, by Hasse. Now "v~\tilde{v}" is "represented" by the two values h~,l~∈Fp\tilde{h}, \tilde{l} \in \mathbb{F}_p.

Note that no decomposition is necessary if the "original value" vv was in Fp\mathbb{F}_p, since Fq\mathbb{F}_q is big enough to hold the lift of any element in Fp\mathbb{F}_p.

Problem 2: Compute Commitment to the Public Input of other side​

To solve the binding issue we will add l,hl, h to the public inputs on the Fp\mathbb{F}_p-side, for simplicity we will describe the case where l,hl, h are the only public inputs in the Fp\mathbb{F}_p-side, which means that the commitment Pp∈Ep(Fq)P_p \in \mathbb{E}_p(\mathbb{F}_q) to the public inputs on the Fp\mathbb{F}_p side is:

Pp=[h]⋅Gh+[l]⋅Gl∈Ep(Fq)P_p = [h] \cdot G_h + [l] \cdot G_l \in \mathbb{E}_p(\mathbb{F}_q)

At this point it is important to note that Ep\mathbb{E}_p is defined over Fq\mathbb{F}_q!

Which means that we can compute Pp∈Ep(Fq)P_p \in \mathbb{E}_p(\mathbb{F}_q) efficiently on the Fq\mathbb{F}_q-side!

Therefore to enforce the binding, we:

  1. Add a sub-circuit which checks: Pp=[h]⋅Gh+[l]⋅Gl∈Ep(Fq),∣h∣=⌊log⁡p⌋∣l∣=1P_p = [h] \cdot G_h + [l] \cdot G_l \in \mathbb{E}_p(\mathbb{F}_q), \\ |h| = \lfloor \log p \rfloor \\ |l| = 1
  2. Add Pp=(x,y)∈Fq×FqP_p = (x, y) \in \mathbb{F}_q \times \mathbb{F}_q to the public input on the Fq\mathbb{F}_q-side.

We recurse onwards...​

At this point the statement of the proof in Fq\mathbb{F}_q-side is: the Fq\mathbb{F}_q-proof is sound, condition on providing an opening of PpP_p that satisfies the Fp\mathbb{F}_p-relation.

At this point you can stop and verify the proof (in the case of a "step proof" you would), by recomputing PpP_p outside the circuit while checking the Fp\mathbb{F}_p-relation manually "in the clear".

However, when recursing (e.g. wrapping in a "wrap proof") we need to "ingest" this public input PpP_p; after all, to avoid blowup in the proof size everything (proofs/accumulators/public inputs etc.) must eventually become part of the witness and every computation covered by a circuit...

To this end, the wrap proof is a proof for the Fp\mathbb{F}_p-relation with the public input PpP_p which additionally verifies the Fq\mathbb{F}_q-proof.

The next "step" proof then verifies this wrap proof which means that PpP_p then becomes part of the witness!

In Pickles​

We can arbitrarily choose which side should compute the public input of the other, in pickles we let "wrap" compute the commitment to the public input.

Enforcing Equality​

Enforces that the public input of the proof verified on the Fr side is equal to the Fp input computed on Fr side.