diff --git a/protocol/protocol.tex b/protocol/protocol.tex index 8ba74d55..918fe5cb 100644 --- a/protocol/protocol.tex +++ b/protocol/protocol.tex @@ -103,9 +103,10 @@ \newcommand{\ViewingKeyLeadByte}{\mathbf{0x??}} \newcommand{\SpendingKeyLeadByte}{\mathbf{0x??}} \newcommand{\AuthPublic}{\mathsf{a_{pk}}} -\newcommand{\AuthPrivate}{\mathsf{a_{sk}}} \newcommand{\DiscloseKey}{\mathsf{a_{vk}}} +\newcommand{\AuthPrivate}{\mathsf{a_{sk}}} \newcommand{\AuthPublicOld}[1]{\mathsf{a^{old}_{pk,\mathnormal{#1}}}} +\newcommand{\DiscloseKeyOld}[1]{\mathsf{a^{old}_{vk,\mathnormal{#1}}}} \newcommand{\AuthPrivateOld}[1]{\mathsf{a^{old}_{sk,\mathnormal{#1}}}} \newcommand{\AuthPublicNew}[1]{\mathsf{a^{new}_{pk,\mathnormal{#1}}}} \newcommand{\AuthPrivateNew}[1]{\mathsf{a^{new}_{sk,\mathnormal{#1}}}} @@ -120,6 +121,7 @@ \newcommand{\TransmitPublicNew}[1]{\mathsf{pk^{new}_{\enc,\mathnormal{#1}}}} \newcommand{\TransmitPrivate}{\mathsf{sk_{enc}}} \newcommand{\Value}{\mathsf{v}} +\newcommand{\ValueNew}[1]{\mathsf{v^{new}_\mathnormal{#1}}} % Coins \newcommand{\Coin}[1]{\mathbf{c}_{#1}} @@ -136,17 +138,16 @@ \newcommand{\hSigInputVersionByte}{\mathbf{0x00}} \newcommand{\Memo}{\mathsf{memo}} \newcommand{\CurveMultiply}{\mathsf{Curve25519}} -\newcommand{\CryptoBox}{\mathsf{crypto\_box}} -\newcommand{\CryptoBoxOpen}{\mathsf{crypto\_box\_open}} -\newcommand{\CryptoBoxSeal}{\mathsf{crypto\_box\_seal}} -\newcommand{\CryptoBoxSpecific}{\mathsf{crypto\_box\_curve25519xsalsa20poly1305}} \newcommand{\DecryptCoin}{\mathtt{DecryptCoin}} \newcommand{\Plaintext}{\mathbf{P}} \newcommand{\Ciphertext}{\mathbf{C}} \newcommand{\Key}{\mathsf{K}} +\newcommand{\Nonce}{\mathsf{nonce}} +\newcommand{\Empty}{\varnothing} \newcommand{\TransmitPlaintext}[1]{\Plaintext^\enc_{#1}} \newcommand{\TransmitCiphertext}[1]{\Ciphertext^\enc_{#1}} \newcommand{\TransmitKey}[1]{\Key^\enc_{#1}} +\newcommand{\TransmitKeyCompare}[1]{\Key^*_{#1}} \newcommand{\DiscloseCiphertext}[1]{\Ciphertext^\disclose_{#1}} \newcommand{\SharedPlaintext}[1]{\Plaintext^\shared_{#1}} \newcommand{\SharedCiphertext}{\Ciphertext^\shared} @@ -178,6 +179,7 @@ \newcommand{\InternalHash}{\mathsf{InternalH}} \newcommand{\Leading}[1]{\mathtt{Leading}_{#1}} \newcommand{\ReplacementCharacter}{\textsf{U+FFFD}} +\newcommand{\CryptoBoxSeal}{\mathsf{crypto\_box\_seal}} % merkle tree \newcommand{\MerkleDepth}{\mathsf{d}} @@ -216,6 +218,7 @@ \newcommand{\vpubNew}{\mathsf{v_{pub}^{new}}} \newcommand{\cOld}[1]{\mathbf{c}_{#1}^\mathsf{old}} \newcommand{\cNew}[1]{\mathbf{c}_{#1}^\mathsf{new}} +\newcommand{\cpNew}[1]{\mathbf{cp}_{#1}^\mathsf{new}} \newcommand{\vOld}[1]{\mathsf{v}_{#1}^\mathsf{old}} \newcommand{\vNew}[1]{\mathsf{v}_{#1}^\mathsf{new}} \newcommand{\NP}{\mathsf{NP}} @@ -294,6 +297,8 @@ with indices $1$ through $\mathrm{N}$ inclusive. For example, $\AuthPublicNew{\mathrm{1}..\NNew}$ means the sequence $[\AuthPublicNew{\mathrm{1}}, \AuthPublicNew{\mathrm{2}}, ...\;\AuthPublicNew{\NNew}]$. +$\Empty$ denotes an empty byte sequence. + \subsection{Cryptographic Functions} $\CRH$ is a collision-resistant hash function. In \Zcash, the $\SHAName$ function @@ -315,42 +320,15 @@ ensuring that the functions are independent. \newcommand{\iminusone}{\hspace{0.3pt}\scriptsize{$i$\hspace{0.6pt}-1}} -\newsavebox{\addrboxa} -\begin{lrbox}{\addrboxa} +\newsavebox{\addrbox} +\begin{lrbox}{\addrbox} \setchanged \begin{bytefield}[bitwidth=0.065em]{512} - \bitbox{242}{256 bit $\AuthPrivate$} & + \bitbox{242}{256 bit $x$} & \bitbox{18}{0} & \bitbox{18}{0} & - \bitbox{186}{$0^{252}$} & - \bitbox{18}{0} & - \bitbox{18}{0} & -\end{bytefield} -\end{lrbox} - -\newsavebox{\addrboxb} -\begin{lrbox}{\addrboxb} -\setchanged -\begin{bytefield}[bitwidth=0.065em]{512} - \bitbox{242}{256 bit $\DiscloseKey$} & - \bitbox{18}{0} & - \bitbox{18}{0} & - \bitbox{186}{$0^{252}$} & - \bitbox{18}{0} & - \bitbox{18}{1} & -\end{bytefield} -\end{lrbox} - -\newsavebox{\addrboxc} -\begin{lrbox}{\addrboxc} -\setchanged -\begin{bytefield}[bitwidth=0.065em]{512} - \bitbox{242}{256 bit $\AuthPrivate$} & - \bitbox{18}{0} & - \bitbox{18}{0} & - \bitbox{186}{$0^{252}$} & - \bitbox{18}{1} & - \bitbox{18}{0} & + \bitbox{174}{$0^{252}$} & + \bitbox{48}{2 bit $t$} & \end{bytefield} \end{lrbox} @@ -392,17 +370,11 @@ need to be aware of how it is associated with this bit-packing.} \begin{equation*} \begin{aligned} -\setchanged \DiscloseKey &\setchanged := \PRFaddr{\AuthPrivate}(0) -&\setchanged = \CRHbox{\addrboxa} \\ -\setchanged \AuthPublic &\setchanged := \PRFaddr{\DiscloseKey}(1) -&\setchanged = \CRHbox{\addrboxb} \\ -\setchanged \TransmitPrivate' &\setchanged := \PRFaddr{\AuthPrivate}(2) -&\setchanged = \CRHbox{\addrboxc} \\ -\setchanged \TransmitPrivate &\setchanged := \Clamp(\TransmitPrivate') & \\ -\sn &:= \PRFsn{\AuthPrivate}(\CoinAddressRand) &= \CRHbox{\snbox} \\ -\h{i} &:= \PRFpk{\AuthPrivate}(i, \hSig) &= \CRHbox{\pkbox} \\ -\setchanged \CoinAddressRandNew{i} &\setchanged := \PRFrho{\CoinAddressPreRand}(i, \hSig) -&\setchanged = \CRHbox{\rhobox} +&\setchanged \PRFaddr{x}(t) &\setchanged := \CRHbox{\addrbox} \\ +\sn =\;& \PRFsn{\AuthPrivate}(\CoinAddressRand) &:= \CRHbox{\snbox} \\ +\h{i} =\;& \PRFpk{\AuthPrivate}(i, \hSig) &:= \CRHbox{\pkbox} \\ +\setchanged \CoinAddressRandNew{i} =\;&\setchanged \PRFrho{\CoinAddressPreRand}(i, \hSig) +&\setchanged := \CRHbox{\rhobox} \end{aligned} \end{equation*} @@ -446,25 +418,25 @@ to: \item obtain a \paymentAddress\changed{ or \viewingKey} from a \spendingKey. \end{itemize} -Each key component, i.e. each of $\AuthPublic$, $\TransmitPublic$, -\changed{$\DiscloseKey$, }$\TransmitPrivate$, and $\AuthPrivate$, is a sequence of -32 bytes. \changed{$\AuthPublic$, $\DiscloseKey$, and $\TransmitPrivate$ are derived -as follows:} +Each key component, i.e. each of $\AuthPrivate$, \changed{$\DiscloseKey$, +}$\AuthPublic$, $\TransmitPrivate$, and $\TransmitPublic$, is a sequence of +32 bytes. + +\changed{ +$\DiscloseKey$, $\AuthPublic$, $\TransmitPrivate$, and $\TransmitPublic$ are +derived as follows: \begin{equation*} \begin{aligned} -\setchanged \DiscloseKey &\setchanged := \PRFaddr{\AuthPrivate}(0) & \hspace{30em} \\ -\setchanged \AuthPublic &\setchanged := \PRFaddr{\DiscloseKey}(1) & \\ -\setchanged \TransmitPrivate &\setchanged := \Clamp(\PRFaddr{\AuthPrivate}(2)) & +\DiscloseKey &:= \PRFaddr{\AuthPrivate}(0) & \hspace{30em} \\ +\AuthPublic &:= \PRFaddr{\DiscloseKey}(1) & \\ +\TransmitPrivate &:= \Clamp(\PRFaddr{\AuthPrivate}(2)) & \\ +\TransmitPublic &:= \CurveMultiply(\TransmitPrivate) \end{aligned} \end{equation*} -\changed{ -$\Clamp$ performs the clamping of Curve25519 private key bits, and +where $\Clamp$ performs the clamping of Curve25519 private key bits, and $\CurveMultiply$ performs point multiplication, both as defined in \cite{Curve25519}. - -Let $\TransmitPublic := \CurveMultiply(\TransmitPrivate)$, i.e. the public key -corresponding to the private key $\TransmitPrivate$. } Users can accept payment from multiple parties with a single @@ -843,17 +815,12 @@ recipient \emph{without} requiring an out-of-band communication channel, the secrets. The recipient's possession of the associated $(\PaymentAddress, \SpendingKey)$ (which contains both $\AuthPublic$ and $\TransmitPrivate$) is used to reconstruct the original \coin \changed{ and \memo}. -\changed{To also transmit these values to a \viewingKey holder for outgoing -\PourTransfers, the \discloseKey $\DiscloseKey$ is used to symmetrically -encrypt them, and also to encrypt the ephemeral secret and address public -keys (to allow the \viewingKey holder to check whether the other encryptions -are valid).} All of these encryptions are combined to form a \coinsCiphertext. -\changed{ -Let $\SymEncrypt{\Key}(\Plaintext)$ be the $\SymSpecific$ encryption -\cite{rfc7539} of plaintext $\Plaintext$ with empty ``additional data", -empty nonce, and key $\Key$. -} +\changed{Several more encryptions are used to also reveal these values to a +holder of a \viewingKey for any of the input \coins, and also to permit them +to check whether the other encryptions are valid.} + +All of the resulting ciphertexts are combined to form a \coinsCiphertext. \newsavebox{\kdfbox} \begin{lrbox}{\kdfbox} @@ -866,6 +833,14 @@ empty nonce, and key $\Key$. \end{bytefield} \end{lrbox} +\newsavebox{\tagbox} +\begin{lrbox}{\tagbox} +\setchanged +\begin{bytefield}[bitwidth=0.032em]{8} + \bitbox{160}{8 bit $i-1$} +\end{bytefield} +\end{lrbox} + \newsavebox{\sharedbox} \begin{lrbox}{\sharedbox} \setchanged @@ -877,42 +852,55 @@ empty nonce, and key $\Key$. \end{bytefield} \end{lrbox} -Let $\TransmitPublicNew{\mathrm{1}..\NNew}$ be the \changed{Curve25519} public keys -for the intended recipient addresses of each new \coin, -\changed{let $\DiscloseKey$ be the sender's \discloseKey,} -and let $\CoinPlaintext{1..\NNew}$ be the \coinPlaintexts. -Let $\TransmitPlaintext{i}$ be the raw encoding of $\CoinPlaintext{i}$. +\subsection{Encryption} \changed{ +Let $\SymEncrypt{\Key}(\Plaintext, \Nonce)$ be the $\SymSpecific$ \cite{rfc7539} +encryption of plaintext $\Plaintext$ with empty ``additional data", nonce $\Nonce$, +and key $\Key$. + +Similarly, let $\SymDecrypt{\Key}(\Ciphertext, \Nonce)$ be the $\SymSpecific$ +decryption of ciphertext $\Ciphertext$ with empty ``additional data", +nonce $\Nonce$, and key $\Key$. The result is either the plaintext byte sequence, +or $\bot$ indicating failure to decrypt. + Define: -\begin{equation*} -\begin{aligned} -\KDF(\DHSecret{i}, \EphemeralPublic, \TransmitPublicNew{i}, i) &:= \FullHashbox{\kdfbox} \\ -\SharedPlaintext{} &:= \Justthebox{\sharedbox} -\end{aligned} -\end{equation*} + +$\KDF(\DHSecret{i}, \EphemeralPublic, \TransmitPublicNew{i}, i) := \FullHashbox{\kdfbox}$. + +$\Tag{i} := \Justthebox{\tagbox}$. } +Let $\TransmitPublicNew{\mathrm{1}..\NNew}$ be the \changed{Curve25519} public keys +for the intended recipient addresses of each new \coin, +\changed{let $\DiscloseKeyOld{\mathrm{1}..\NOld}$ be the \discloseKey for each of +the addresses from which the old \coins are sent,} and let $\CoinPlaintext{1..\NNew}$ +be the \coinPlaintexts. +Let $\TransmitPlaintext{i}$ be the raw encoding of $\CoinPlaintext{i}$. + Then to encrypt: \begin{itemize} \changed{ - \item Generate a new Curve25519 (public, private) key pair: -$(\EphemeralPublic, \EphemeralPrivate)$. + \item Let $\SharedPlaintext{} := \Justthebox{\sharedbox}$. + \item \todo{$\SharedPlaintext{}$ needs to include $\TransmitKey{1..\NNew}$.} + \item Generate a new Curve25519 (public, private) key pair +$(\EphemeralPublic, \EphemeralPrivate)$, and a new $\SymSpecific$ key $\SharedKey{}$. \item For $i$ in $\{1..\NNew\}$, \begin{itemize} \item Let $\DHSecret{i} := \CurveMultiply(\TransmitPublicNew{i}, \EphemeralPrivate)$. \item Let $\TransmitKey{i} := \KDF(\DHSecret{i}, \EphemeralPublic, \TransmitPublicNew{i}, i)$. - \item Let $\TransmitCiphertext{i} := \SymEncrypt{\TransmitKey{i}}(\TransmitPlaintext{i})$. + \item Let $\TransmitCiphertext{i} := +\SymEncrypt{\TransmitKey{i}}(\TransmitPlaintext{i}, \Empty)$. \end{itemize} - \item Let $\SharedKey{} := ...$. - \item Let $\SharedCiphertext := \SymEncrypt{\SharedKey{}}(\SharedPlaintext{})$. \item For $i$ in $\{1..\NOld\}$, \begin{itemize} - \item Let $\DiscloseCiphertext{i} := \SymEncrypt{\DiscloseKey{i}}(\SharedKey{})$. + \item Let $\DiscloseCiphertext{i} := +\SymEncrypt{\DiscloseKeyOld{i}}(\SharedKey{}, \Tag{i})$. \end{itemize} + \item Let $\SharedCiphertext := \SymEncrypt{\SharedKey{}}(\SharedPlaintext{}, \Empty)$. } \end{itemize} @@ -920,6 +908,8 @@ The resulting \coinsCiphertext is $\changed{(\EphemeralPublic, \TransmitCiphertext{\mathrm{1}..\NNew}, \DiscloseCiphertext{\mathrm{1}..\NOld}, \SharedCiphertext)}$. +\subsection{Decryption by a Recipient} + Let $(\TransmitPublic, \TransmitPrivate)$ be the recipient's \changed{Curve25519} (public, private) key pair, and let $\cmNew{\mathrm{1}..\NNew}$ be the coin commitments of each output coin. Then for each $i$ in $\{1..\NNew\}$, the recipient @@ -928,22 +918,21 @@ will attempt to decrypt that ciphertext component as follows: \changed{ \begin{itemize} \item Let $\DHSecret{i} := \CurveMultiply(\EphemeralPublic, \TransmitPrivate)$. - \item Return $\DecryptCoin(\DHSecret{i}, \EphemeralPublic, \TransmitPublicNew{i}, i, -\TransmitCiphertext{i}, \cmNew{i}).$ -\end{itemize} - -$\DecryptCoin(\DHSecret{i}, \EphemeralPublic, \TransmitPublicNew{i}, i, -\TransmitCiphertext{i}, \cmNew{i})$ is defined as follows: - -\begin{itemize} \item Let $\TransmitKey{i} := \KDF(\DHSecret{i}, \EphemeralPublic, \TransmitPublicNew{i}, i)$. - \item Let $\TransmitPlaintext{i} := \SymDecrypt{\TransmitKey{i}}(\TransmitCiphertext{i})$. + \item Return $\DecryptCoin(\TransmitKey{i}, \TransmitCiphertext{i}, \cmNew{i}).$ +\end{itemize} + +$\DecryptCoin(\TransmitKey{i}, \TransmitCiphertext{i}, \cmNew{i})$ is defined as follows: + +\begin{itemize} + \item Let $\TransmitPlaintext{i} := +\SymDecrypt{\TransmitKey{i}}(\TransmitCiphertext{i}, \Empty)$. \item If $\TransmitPlaintext{i} = \bot$, return $\bot$. - \item Extract $\CoinPlaintext{i} := (\AuthPublic, \Value, \CoinAddressRand, -\CoinCommitRand, \Memo)$ from $\TransmitPlaintext{i}$. - \item If $\CoinCommitment(\Coin{i}) \neq \cmNew{i}$, return $\bot$, else - return $\CoinPlaintext{i}$. + \item Extract $\CoinPlaintext{i} = (\AuthPublicNew{i}, \ValueNew{i}, +\CoinAddressRandNew{i}, \CoinCommitRandNew{i}, \Memo_i)$ from $\TransmitPlaintext{i}$. + \item If $\CoinCommitment((\AuthPublicNew{i}, \ValueNew{i}, \CoinAddressRandNew{i}, +\CoinCommitRandNew{i})) \neq \cmNew{i}$, return $\bot$, else return $\CoinPlaintext{i}$. \end{itemize} } @@ -961,35 +950,45 @@ the transaction in which a coin was output to no longer be on the consensus blockchain. \changed{ +\subsection{Decryption by a Viewing Key Holder} + Let $\DiscloseKey{}$ be a \viewingKey holder's \discloseKey. Then for each \PourDescription in its \blockchainview, the \viewingKey holder will attempt to decrypt the corresponding \coinsCiphertext as follows: -} -\changed{ \begin{enumerate} \item Set $\SharedPlaintext{} := \bot$. \item For $i$ in $\{1..\NNew\}$, \begin{itemize} - \item Let $\SharedKey{i} := \SymDecrypt{\DiscloseKey{}}(\DiscloseCiphertext{i}, \Tag{i})$. + \item Let $\SharedKey{i} := +\SymDecrypt{\DiscloseKey{}}(\DiscloseCiphertext{i}, \Tag{i})$. \item If $\SharedKey{i} = \bot$ then continue with the next $i$. - \item Let $\SharedPlaintext{i} := \SymDecrypt{\SharedKey{i}}(\SharedCiphertext)$. + \item Let $\SharedPlaintext{i} := +\SymDecrypt{\SharedKey{i}}(\SharedCiphertext, \Empty)$. \item If $\SharedPlaintext{i} = \bot$ then continue with the next $i$. \item Set $\SharedPlaintext{} := \SharedPlaintext{i}$ and exit the loop. \end{itemize} \item If $\SharedPlaintext{} = \bot$ (i.e. it was not set in the loop), then this -transaction does not contain any information decryptable by the \viewingKey; return $\bot$. - \item Extract $\TransmitPublicNew{\mathrm{1}..\NNew}$ and $\EphemeralPrivate$ -from $\SharedPlaintext{}$. +transaction does not contain any information decryptable by the \viewingKey; set +$\CoinPlaintext{i} = \bot$ for $i$ in $\{1..\NNew\}$ and return +$\CoinPlaintext{\mathrm{1}..\NNew}$. + \item Extract $\TransmitKey{1..\NNew}$, $\TransmitPublicNew{\mathrm{1}..\NNew}$, +and $\EphemeralPrivate$ from $\SharedPlaintext{}$. \item For $i$ in $\{1..\NNew\}$, \begin{itemize} + \item Let $\CoinPlaintext{i} := +\DecryptCoin(\TransmitKey{i}, \TransmitCiphertext{i}, \cmNew{i})$. \item Let $\DHSecret{i} := \CurveMultiply(\TransmitPublicNew{i}, \EphemeralPrivate)$. - \item Let $\CoinPlaintext{i} := \DecryptCoin(\DHSecret{i}, \EphemeralPublic, -\TransmitPublicNew{i}, i, \TransmitCiphertext{i}, \cmNew{i}).$ + \item Let $\TransmitKeyCompare{i} := \KDF(\DHSecret{i}, \EphemeralPublic, +\TransmitPublicNew{i}, i)$. + \item If $\CoinPlaintext{i} \neq \bot$ and +$\TransmitKeyCompare{i} \neq \TransmitKey{i}$ then set the \memo +of $\CoinPlaintext{i}$ to be $\bot$ (indicating that, although this is a valid +coin, the recipient would not have been able to decrypt it, and that the \memo +cannot be verified). \end{itemize} \item Return $\CoinPlaintext{\mathrm{1}..\NNew}$. \end{enumerate} -} If a party holds more than one \viewingKey, it may optimize the above procedure by performing the loop in step 2 for the $\DiscloseKey{}$ of each @@ -998,22 +997,21 @@ decrypts correctly is the one that should be used in step 4 onward. (However, additional information is provided by which \viewingKey was able to decrypt each $\DiscloseCiphertext{i}$.) -\changed{ The public key encryption used in this part of the protocol is based loosely on -the $\CryptoBoxSeal$ algorithm defined in libsodium \cite{cryptoboxseal}, but -with the following differences: +other encryption schemes based on Diffie-Hellman over an elliptic curve, such +as ECIES or the $\CryptoBoxSeal$ algorithm defined in libsodium \cite{cryptoboxseal}. +Note that: \begin{itemize} \item The same ephemeral key is used for all encryptions to the recipient keys in a given \PourDescription. - \item The nonce for each ciphertext component depends on the index $i$. - The particular nonce construction is chosen so that a known-nonce - distinguisher for $\mathsf{Salsa20}$ would not directly lead to a break - of the IK-CCA (key privacy) property. - \item $\FullHash$ (the full hash, not the compression function) is used instead - of $\mathsf{blake2b}$. + \item In addition to the Diffie-Hellman secret, the KDF takes as input the + public keys of both parties, and the index $i$. + \item The nonce parameter to $\SymSpecific$ is not used for the public key + encryption. \item The ephemeral secret $\EphemeralPrivate$ is included together with - the \transmitKeypair public keys of the recipients, encrypted to the - \discloseKey. This allows a \viewingKey holder to check whether the + the \transmitKeypair public keys of the recipients, symmetrically + encrypted to the \discloseKey. + This allows a \viewingKey holder to check whether the indicated recipients would be able to decrypt a given component, and if so to decrypt the memo field. (We do not rely on this to ensure that a \viewingKey holder can decrypt the other components of the