1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//! Spend authority gadget – 1:1 copy from the upstream Orchard action circuit.
//!
//! Upstream source (as of 2025-05-01):
//! <https://github.com/zcash/orchard/blob/main/src/circuit.rs#L542-L558>
//!
//! The Orchard action circuit proves spend authority as follows:
//!
//! ```text
//! rk = [alpha] * SpendAuthG + ak_P
//! ```
//!
//! where `alpha` is a randomizer scalar, `SpendAuthG` is the Orchard spend
//! authorization generator (a Pallas fixed base), and `ak_P` is the spend
//! validating key. The verifier then checks that the transaction signature is
//! valid under `rk`, linking the ZKP to the signature without revealing `ak`.
//!
//! Reference: <https://zips.z.cash/protocol/protocol.pdf#spendauthsig>
//! (§ 4.15, Spend Authorization Signature)
//!
//! This module extracts that logic into a reusable gadget so that both the
//! voting delegation and vote-proof circuits can share the exact same
//! constraint code as the upstream Orchard action circuit.
use ;
use pallas;
use ;
use ;
/// Proves spend authority: `rk = [alpha] * SpendAuthG + ak_P`, then constrains
/// `rk` to the public instance columns at the given rows.
///
/// This is a 1:1 copy of the spend authority check from the upstream Orchard
/// action circuit:
/// <https://github.com/zcash/orchard/blob/main/src/circuit.rs#L542-L558>
///
/// # Arguments
///
/// * `ecc_chip` – The ECC chip used for curve arithmetic.
/// * `layouter` – Circuit layouter.
/// * `alpha` – The randomizer scalar witness value.
/// * `ak_P` – The spend validating key as a curve point.
/// * `primary` – The instance column for public inputs.
/// * `rk_x_row` – Row index in `primary` for the rk x-coordinate.
/// * `rk_y_row` – Row index in `primary` for the rk y-coordinate.
///
/// ---
///
/// **Upstream Orchard equivalent** (for easy review – this function produces
/// the exact same constraints):
///
/// ```text
/// // https://github.com/zcash/orchard/blob/main/src/circuit.rs
/// //
/// // Spend authority (https://p.z.cash/ZKS:action-spend-authority)
/// {
/// let alpha =
/// ScalarFixed::new(ecc_chip.clone(), layouter.namespace(|| "alpha"), self.alpha)?;
///
/// // alpha_commitment = [alpha] SpendAuthG
/// let (alpha_commitment, _) = {
/// let spend_auth_g = OrchardFixedBasesFull::SpendAuthG;
/// let spend_auth_g = FixedPoint::from_inner(ecc_chip.clone(), spend_auth_g);
/// spend_auth_g.mul(layouter.namespace(|| "[alpha] SpendAuthG"), alpha)?
/// };
///
/// // [alpha] SpendAuthG + ak_P
/// let rk = alpha_commitment.add(layouter.namespace(|| "rk"), &ak_P)?;
///
/// // Constrain rk to equal public input
/// layouter.constrain_instance(rk.inner().x().cell(), config.primary, RK_X)?;
/// layouter.constrain_instance(rk.inner().y().cell(), config.primary, RK_Y)?;
/// }
/// ```