Skip to content

zorch.logup_gkr.stage

Dense LogUp-GKR role implementations.

The claim types and the proof envelope are layout-independent, so the jagged roles (jagged_stage) reduce the same LogUpOutputClaim to the same InputLayerClaim and a consumer can swap one layout for the other.

LogUpOutputClaim dataclass

Public LogUp circuit-output claim and verifier-owned layer count.

Source code in zorch/logup_gkr/stage.py
28
29
30
31
32
33
@dataclass(frozen=True)
class LogUpOutputClaim:
    """Public LogUp circuit-output claim and verifier-owned layer count."""

    output: LogUpGkrOutput
    layers: int

InputLayerClaim dataclass

Numerator and denominator evaluations claimed at the input layer.

Source code in zorch/logup_gkr/stage.py
36
37
38
39
40
41
42
@dataclass(frozen=True)
class InputLayerClaim:
    """Numerator and denominator evaluations claimed at the input layer."""

    numerator: Array
    denominator: Array
    point: Array

GkrProof dataclass

Bases: Generic[LayerProofT]

One conditional reduction-proof section per GKR layer.

Parameterized by the layer proof because the pyramid's shape is the protocol and the layer's sumcheck transcript is the layout.

Source code in zorch/logup_gkr/stage.py
45
46
47
48
49
50
51
52
53
@dataclass(frozen=True)
class GkrProof(Generic[LayerProofT]):
    """One conditional reduction-proof section per GKR layer.

    Parameterized by the layer proof because the pyramid's shape is the
    protocol and the layer's sumcheck transcript is the layout.
    """

    layers: tuple[LayerProofT, ...]

LogUpGkrProver

Bases: ProverStage[LogUpOutputClaim, GkrLayer, InputLayerClaim, GkrProof[LayerProof]]

Prove an output claim conditional on an input-layer claim.

Source code in zorch/logup_gkr/stage.py
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
class LogUpGkrProver(
    ProverStage[LogUpOutputClaim, GkrLayer, InputLayerClaim, GkrProof[LayerProof]]
):
    """Prove an output claim conditional on an input-layer claim."""

    def __init__(self, challenges: ChallengePolicy) -> None:
        self.challenges = challenges

    def prove(
        self,
        claim: LogUpOutputClaim,
        witness: GkrLayer,
        transcript: Transcript,
    ) -> ProveResult[InputLayerClaim, GkrProof[LayerProof]]:
        if witness.num_row_variables != claim.layers:
            raise ValueError(
                f"claim expects {claim.layers} GKR layers, "
                f"witness needs {witness.num_row_variables}"
            )
        pyramid = build_pyramid(witness)
        carry, transcript = bind_output(claim.output, transcript, self.challenges)
        carry, transcript, proofs = prove_rounds(
            (
                ProverLayerRound(layer, self.challenges)
                for layer in reversed(pyramid[:-1])
            ),
            carry,
            transcript,
        )
        reduction_proofs = tuple(proofs)
        if len(reduction_proofs) != claim.layers:
            raise AssertionError(
                f"built {len(reduction_proofs)} GKR proofs for {claim.layers} layers"
            )
        return ProveResult(
            _input_claim(carry),
            GkrProof(reduction_proofs),
            transcript,
        )

LogUpGkrVerifier

Bases: VerifierStage[LogUpOutputClaim, InputLayerClaim, GkrProof[LayerProof]]

Verify an output-to-input-layer LogUp-GKR reduction.

Source code in zorch/logup_gkr/stage.py
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
class LogUpGkrVerifier(
    VerifierStage[LogUpOutputClaim, InputLayerClaim, GkrProof[LayerProof]]
):
    """Verify an output-to-input-layer LogUp-GKR reduction."""

    def __init__(self, challenges: ChallengePolicy) -> None:
        self.challenges = challenges

    def verify(
        self,
        claim: LogUpOutputClaim,
        reduction_proof: GkrProof[LayerProof],
        transcript: Transcript,
    ) -> VerifyResult[InputLayerClaim]:
        if len(reduction_proof.layers) != claim.layers:
            raise ValueError(
                f"expected {claim.layers} GKR layers, "
                f"got {len(reduction_proof.layers)}"
            )
        carry, transcript = bind_output(claim.output, transcript, self.challenges)
        carry, transcript, ok = verify_rounds(
            (VerifierLayerRound(self.challenges) for _ in range(claim.layers)),
            carry,
            reduction_proof.layers,
            transcript,
        )
        return VerifyResult(_input_claim(carry), transcript, ok)