From 0abc0ef11a0e5e94f4eaa0b17210a684d8249107 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 20 Jan 2021 14:06:03 +0000 Subject: [PATCH] book: Revert to the previous nullifier design We examined the nullifier designs more closely, and determined that the previously-selected design was actually fine, but for a somewhat-subtle reason: even though an adversary with knowledge of a victim's full viewing key could choose psi to cancel out Hash_nk(rho), the nullifier still directly depends on rho via the note commitment. --- book/src/design/nullifiers.md | 83 +++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 37 deletions(-) diff --git a/book/src/design/nullifiers.md b/book/src/design/nullifiers.md index 7471187c..20e3cb13 100644 --- a/book/src/design/nullifiers.md +++ b/book/src/design/nullifiers.md @@ -2,34 +2,25 @@ The nullifier design we use for Orchard is -$$\mathsf{nf} = [Hash_{\mathsf{nk}}(\psi)] H + [\mathsf{rnf}] \mathcal{I},$$ +$$\mathsf{nf} = [F_{\mathsf{nk}}(\rho) + \psi \pmod{p}] \mathcal{G} + \mathsf{cm},$$ where: -- $Hash$ is a keyed circuit-efficient hash (such as Rescue). -- $GH$ is a cryptographic hash into the group (such as BLAKE2s with simplified SWU). -- $\mathcal{I}$ is a fixed base, independent of any others returned by $GH$. -- $H$ is a base unique to this output. - - For non-zero-valued notes, $H = GH(\rho)$. As with $\mathsf{h_{Sig}}$ in Sprout, - $\rho$ includes the nullifiers of any Orchard notes being spent in the same action. - Given that an action consists of a single spend and a single output, we set $\rho$ to - be the nullifier of the spent note. - - For zero-valued notes, $H$ is constrained by the circuit to a fixed base independent - of $\mathcal{I}$ and any others returned by $GH$. +- $F$ is a keyed circuit-efficient PRF (such as Rescue). +- $\rho$ is unique to this output. As with $\mathsf{h_{Sig}}$ in Sprout, $\rho$ includes + the nullifiers of any Orchard notes being spent in the same action. Given that an action + consists of a single spend and a single output, we set $\rho$ to be the nullifier of the + spent note. - $\psi$ is sender-controlled randomness. It is not required to be unique, and in practice is derived from both $\rho$ and a sender-selected random value $\mathsf{rseed}$: - $\psi = KDF^\psi(\rho, \mathsf{rseed})$. -- $\mathsf{rnf}$ is a blinding scalar, similarly generated as - $\mathsf{rnf} = KDF^\mathsf{rnf}(\rho, \mathsf{rseed})$. + $$\psi = KDF^\psi(\rho, \mathsf{rseed}).$$ +- $\mathcal{G}$ is a fixed independent base. This gives a note structure of -$$(addr, v, H, \psi, \mathsf{rnf}, \mathsf{rcm}).$$ +$$(addr, v, \rho, \psi, \mathsf{rcm}).$$ -The note plaintext includes $\mathsf{rseed}$ in place of $\psi$, $\mathsf{rnf}$, and -$\mathsf{rcm}$. $H$ is omitted entirely from the action: -- Consensus nodes directly derive $GH(\rho)$ and provide it as a public input to the - circuit (which ignores it for zero-valued notes, as with the commitment tree anchor). -- The recipient can recompute the correct $H$ given their additional knowledge of $v$. +The note plaintext includes $\mathsf{rseed}$ in place of $\psi$ and $\mathsf{rcm}$, and +omits $\rho$ (which is a public part of the action). ## Security properties @@ -60,6 +51,8 @@ We care about several security properties for our nullifiers: We assume (and instantiate elsewhere) the following primitives: +- $GH$ is a cryptographic hash into the group (such as BLAKE2s with simplified SWU), used + to derive all fixed independent bases. - $E$ is an elliptic curve (such as Pallas). - $KDF$ is the note encryption key derivation function. @@ -69,19 +62,25 @@ $$ \begin{array}{|l|l|} \text{Balance} & DL_E \\ \text{Note Privacy} & HashDH^{KDF}_E \\ -\text{Note Privacy (OOB)} & \text{Perfect} \\ -\text{Spend Unlinkability} & DDH_E^\dagger \vee PRF_{Hash} \\ -\text{Faerie Resistance} & (RO_{GH} \vee (Coll_{GH} \wedge RO_{Hash})) \wedge DL_E \\ +\text{Note Privacy (OOB)} & \text{Near perfect} \ddagger \\ +\text{Spend Unlinkability} & DDH_E^\dagger \vee PRF_F \\ +\text{Faerie Resistance} & DL_E \\ \end{array} $$ -$HashDH^{F}_E$ is computational Diffie-Hellman using $F$ for the key derivation, with +$HashDH^{KDF}_E$ is computational Diffie-Hellman using $KDF$ for the key derivation, with one-time ephemeral keys. This assumption is heuristically weaker than $DDH_E$ but stronger than $DL_E$. +We omit $RO_{GH}$ as a security assumption because we only rely on the random oracle +applied to fixed inputs defined by the protocol, i.e. to generate the fixed base +$\mathcal{G}$, not to attacker-specified inputs. + > $\dagger$ We additionally assume that for any input $x$, -> $\{Hash_{\mathsf{nk}}(x) : \mathsf{nk} \in E\}$ gives a scalar in an adequate range for -> $DDH_E$. (Otherwise, $Hash$ could be trivial, e.g. independent of $\mathsf{nk}$.) +> $\{F_{\mathsf{nk}}(x) : \mathsf{nk} \in E\}$ gives a scalar in an adequate range for +> $DDH_E$. (Otherwise, $F$ could be trivial, e.g. independent of $\mathsf{nk}$.) +> +> $\ddagger$ Statistical distance $< 2^{-167.8}$ from perfect. ## Considered alternatives @@ -92,26 +91,36 @@ not fully rigorous. $$ \begin{array}{|c|l|c|c|c|c|c|} \hline -\mathsf{nf} & Note & \text{Balance} & \text{Note Privacy} & \text{Note Privacy (OOB)} & \text{Spend Unlinkability} & \text{Faerie Resistance} & \text{Rejected because} \\\hline +\mathsf{nf} & Note & \text{Balance} & \text{Note Privacy} & \text{Note Privacy (OOB)} & \text{Spend Unlinkability} & \text{Faerie Resistance} & \text{Reason not to use} \\\hline [\mathsf{nk}] [\theta] H & (addr, v, H, \theta, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & \text{Perfect} & DDH_E & RO_{GH} \wedge DL_E & \text{No SU for DL-breaking} \\\hline [\mathsf{nk}] H + [\mathsf{rnf}] \mathcal{I} & (addr, v, H, \mathsf{rnf}, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & \text{Perfect} & DDH_E & RO_{GH} \wedge DL_E & \text{No SU for DL-breaking} \\\hline Hash([\mathsf{nk}] [\theta] H) & (addr, v, H, \theta, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & \text{Perfect} & DDH_E \vee Pre_{Hash} & Coll_{Hash} \wedge RO_{GH} \wedge DL_E & Coll_{Hash} \text{ for FR} \\\hline Hash([\mathsf{nk}] H + [\mathsf{rnf}] \mathcal{I}) & (addr, v, H, \mathsf{rnf}, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & \text{Perfect} & DDH_E \vee Pre_{Hash} & Coll_{Hash} \wedge RO_{GH} \wedge DL_E & Coll_{Hash} \text{ for FR} \\\hline -[Hash_{\mathsf{nk}}(\psi)] [\theta] H & (addr, v, H, \theta, \psi, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & \text{Perfect} & DDH_E^\dagger \vee PRF_{Hash} & RO_{GH} \wedge DL_E & 2 \text{ variable-base scalar mults} \\\hline -[Hash_{\mathsf{nk}}(\psi)] \mathcal{G} + [\theta] H & (addr, v, H, \theta, \psi, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & \text{Perfect} & DDH_E^\dagger \vee PRF_{Hash} & RO_{GH} \wedge DL_E \\\hline -[Hash_{\mathsf{nk}}(\psi)] H + \mathsf{cm} & (addr, v, H, \psi, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & PRF_{Hash} & DDH_E^\dagger \vee PRF_{Hash} & (RO_{GH} \vee (Coll_{GH} \wedge RO_{Hash})) \wedge DL_E & PRF_{Hash} \text{ for NP(OOB)} \\\hline -[Hash_{\mathsf{nk}}(\rho, \psi)] \mathcal{G} + \mathsf{cm} & (addr, v, \rho, \psi, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & PRF_{Hash} & DDH_E^\dagger \vee PRF_{Hash} & Coll_{Hash} \wedge DL_E & PRF_{Hash} \text{ for NP(OOB)} \\\hline -[Hash_{\mathsf{nk}}(\rho)] \mathcal{G} + \mathsf{cm} & (addr, v, \rho, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & PRF_{Hash} & DDH_E^\dagger \vee PRF_{Hash} & Coll_{Hash} \wedge DL_E & PRF_{Hash} \text{ for NP(OOB)} \\\hline -[Hash_{\mathsf{nk}}(\rho, \psi)] \mathcal{G} + Commit^{\mathsf{nf}}_{\mathsf{rnf}}(v, \rho) & (addr, v, \rho, \mathsf{rnf}, \psi, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & \text{Perfect} & DDH_E^\dagger \vee PRF_{Hash} & Coll_{Hash} \wedge DL_E & Coll_{Hash} \text{ for FR} \\\hline -[Hash_{\mathsf{nk}}(\rho)] \mathcal{G} + Commit^{\mathsf{nf}}_{\mathsf{rnf}}(v, \rho) & (addr, v, \rho, \mathsf{rnf}, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & \text{Perfect} & DDH_E^\dagger \vee PRF_{Hash} & Coll_{Hash} \wedge DL_E & Coll_{Hash} \text{ for FR} \\\hline -[Hash_{\mathsf{nk}}(\rho, \psi)] \mathcal{G} + [\mathsf{rnf}] \mathcal{I} + \mathsf{cm} & (addr, v, \rho, \mathsf{rnf}, \psi, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & \text{Perfect} & DDH_E^\dagger \vee PRF_{Hash} & Coll_{Hash} \wedge DL_E & Coll_{Hash} \text{ for FR} \\\hline -[Hash_{\mathsf{nk}}(\rho)] \mathcal{G} + [\mathsf{rnf}] \mathcal{I} + \mathsf{cm} & (addr, v, \rho, \mathsf{rnf}, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & \text{Perfect} & DDH_E^\dagger \vee PRF_{Hash} & Coll_{Hash} \wedge DL_E & Coll_{Hash} \text{ for FR} \\\hline +[F_{\mathsf{nk}}(\psi)] [\theta] H & (addr, v, H, \theta, \psi, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & \text{Perfect} & DDH_E^\dagger \vee PRF_F & RO_{GH} \wedge DL_E & \text{Performance (2 variable-base)} \\\hline +[F_{\mathsf{nk}}(\psi)] H + [\mathsf{rnf}] \mathcal{I} & (addr, v, H, \mathsf{rnf}, \psi, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & \text{Perfect} & DDH_E^\dagger \vee PRF_F & RO_{GH} \wedge DL_E & \text{Performance (1 variable- + 1 fixed-base)} \\\hline +[F_{\mathsf{nk}}(\psi)] \mathcal{G} + [\theta] H & (addr, v, H, \theta, \psi, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & \text{Perfect} & DDH_E^\dagger \vee PRF_F & RO_{GH} \wedge DL_E & \text{Performance (1 variable- + 1 fixed-base)} \\\hline +[F_{\mathsf{nk}}(\psi)] H + \mathsf{cm} & (addr, v, H, \psi, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & DDH_E^\dagger & DDH_E^\dagger \vee PRF_F & RO_{GH} \wedge DL_E & \text{NP(OOB) not perfect} \\\hline +[F_{\mathsf{nk}}(\rho, \psi)] \mathcal{G} + \mathsf{cm} & (addr, v, \rho, \psi, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & DDH_E^\dagger & DDH_E^\dagger \vee PRF_F & DL_E & \text{NP(OOB) not perfect} \\\hline +[F_{\mathsf{nk}}(\rho)] \mathcal{G} + \mathsf{cm} & (addr, v, \rho, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & DDH_E^\dagger & DDH_E^\dagger \vee PRF_F & DL_E & \text{NP(OOB) not perfect} \\\hline +[F_{\mathsf{nk}}(\rho, \psi)] \mathcal{G_v} + [\mathsf{rnf}] \mathcal{I} & (addr, v, \rho, \mathsf{rnf}, \psi, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & \text{Perfect} & DDH_E^\dagger \vee PRF_F & Coll_F \wedge DL_E & Coll_F \text{ for FR} \\\hline +[F_{\mathsf{nk}}(\rho)] \mathcal{G_v} + [\mathsf{rnf}] \mathcal{I} & (addr, v, \rho, \mathsf{rnf}, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & \text{Perfect} & DDH_E^\dagger \vee PRF_F & Coll_F \wedge DL_E & Coll_F \text{ for FR} \\\hline +[F_{\mathsf{nk}}(\rho) + \psi \pmod{p}] \mathcal{G_v} & (addr, v, \rho, \psi, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & \text{Near perfect} \ddagger & DDH_E^\dagger \vee PRF_F & \color{red}{\text{broken}} & \text{broken for FR} \\\hline +[F_{\mathsf{nk}}(\rho, \psi)] \mathcal{G} + Commit^{\mathsf{nf}}_{\mathsf{rnf}}(v, \rho) & (addr, v, \rho, \mathsf{rnf}, \psi, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & \text{Perfect} & DDH_E^\dagger \vee PRF_F & DL_E & \text{Performance (2 fixed-base)} \\\hline +[F_{\mathsf{nk}}(\rho)] \mathcal{G} + Commit^{\mathsf{nf}}_{\mathsf{rnf}}(v, \rho) & (addr, v, \rho, \mathsf{rnf}, \mathsf{rcm}) & DL_E & HashDH^{KDF}_E & \text{Perfect} & DDH_E^\dagger \vee PRF_F & DL_E & \text{Performance (2 fixed-base)} \\\hline \end{array} $$ In the above alternatives: -- $\mathcal{G}$ is an fixed independent base, independent of $\mathcal{I}$ and any others +- $Hash$ is a keyed circuit-efficient hash (such as Rescue). +- $\mathcal{I}$ is an fixed independent base, independent of $\mathcal{G}$ and any others returned by $GH$. +- $\mathcal{G_v}$ is a pair of fixed independent bases (independent of all others), where + the specific choice of base depends on whether the note has zero value. +- $H$ is a base unique to this output. + - For non-zero-valued notes, $H = GH(\rho)$. As with $\mathsf{h_{Sig}}$ in Sprout, + $\rho$ includes the nullifiers of any Orchard notes being spent in the same action. + - For zero-valued notes, $H$ is constrained by the circuit to a fixed base independent + of $\mathcal{I}$ and any others returned by $GH$. The $Commit^{\mathsf{nf}}$ variants enabled nullifier domain separation based on note value, without directly depending on $\mathsf{cm}$ (which in its native type is a base