For Sprout, add an explicit lead byte field to note plaintexts.

For Sapling, define note plaintext lead bytes as just bytes (so that decoding always succeeds and error handling is more explicit).

Signed-off-by: Daira Hopwood <daira@jacaranda.org>
This commit is contained in:
Daira Hopwood 2020-06-26 19:09:21 +01:00
parent a3e4403f50
commit 3e98e63a6c
1 changed files with 33 additions and 24 deletions

View File

@ -931,6 +931,7 @@ electronic commerce and payment, financial privacy, proof of work, zero knowledg
\newcommand{\notePlaintext}{\term{note plaintext}}
\newcommand{\notePlaintexts}{\terms{note plaintext}}
\newcommand{\notePlaintextLeadByte}{\term{note plaintext lead byte}}
\newcommand{\notePlaintextLeadBytes}{\terms{note plaintext lead byte}}
\newcommand{\noteCiphertext}{\termandindex{transmitted note ciphertext}{transmitted note ciphertext (Sapling)}}
\newcommand{\noteCiphertexts}{\termandindex{transmitted note ciphertexts}{transmitted note ciphertext (Sapling)}}
\newcommand{\notesCiphertext}{\termandindex{transmitted notes ciphertext}{transmitted notes ciphertext (Sprout)}}
@ -2814,7 +2815,8 @@ Each \SproutOrNothing{} \defining{\notePlaintext} (denoted $\NotePlaintext{}$) c
\vspace{-1ex}
\begin{formulae}
\item $(\Value \typecolon \ValueType, \NoteAddressRand \typecolon \PRFOutputSprout,
\item $(\changed{\NotePlaintextLeadByte \typecolon \byte,\ }
\Value \typecolon \ValueType, \NoteAddressRand \typecolon \PRFOutputSprout,
\NoteCommitRand \typecolon \NoteCommitSproutTrapdoor\changed{, \Memo \typecolon \MemoType})$.
\end{formulae}
@ -2826,12 +2828,12 @@ The \notePlaintext in each \outputDescription is encrypted to the
Each \Sapling{} \defining{\notePlaintext} (denoted $\NotePlaintext{}$) consists of
\begin{formulae}
\item $(\NotePlaintextLeadByte \typecolon \setof{\hexint{01}\canopy{, \hexint{02}}},
\item $(\NotePlaintextLeadByte \typecolon \byte,
\Diversifier \typecolon \DiversifierType, \Value \typecolon \ValueType,
\NoteCommitRandBytesOrSeedBytes \typecolon \NoteSeedBytesType, \Memo \typecolon \MemoType)$
\end{formulae}
The fields \notcanopy{$\Diversifier$, $\Value$, and $\NoteCommitRandBytes$}\canopy{$\Diversifier$ and $\Value$}
The fields \notcanopy{$\Diversifier$, $\Value$, and $\NoteCommitRandBytes$}\notbeforecanopy{$\Diversifier$ and $\Value$}
are as defined in \crossref{notes}.
\canopy{
@ -4391,7 +4393,7 @@ Then it creates each output \note with index $i \typecolon \setofNew$:
}
\item Compute $\cm_i =
\NoteCommitSprout{\NoteCommitRand_i}(\AuthPublicSub{i}, \Value_i, \NoteAddressRand_i)$.
\item Let $\NotePlaintext{i} = (\Value_i, \NoteAddressRand_i, \NoteCommitRand_i, \Memo_i)$.
\item Let $\NotePlaintext{i} = (\changed{\hexint{00},\ } \Value_i, \NoteAddressRand_i, \NoteCommitRand_i\changed{, \Memo_i})$.
\end{itemize}
$\NotePlaintext{\allNew}$ are then encrypted to the recipient \transmissionKeys
@ -5472,11 +5474,12 @@ is defined as follows:
\item let $\TransmitPlaintext{i} =
\SymDecrypt{\TransmitKey{i}}(\TransmitCiphertext{i})$
\item if $\TransmitPlaintext{i} = \bot$, return $\bot$
\item extract $\NotePlaintext{i} = (\Value_i \typecolon \ValueType,
\item extract $\NotePlaintext{i} = (\NotePlaintextLeadByte_i \typecolon \byte,
\Value_i \typecolon \ValueType,
\NoteAddressRand_i \typecolon \PRFOutputSprout,
\NoteCommitRand_i \typecolon \NoteCommitSproutTrapdoor,
\Memo_i \typecolon \MemoType)$ from $\TransmitPlaintext{i}$
\item if $\NoteCommitmentSprout((\AuthPublic, \Value_i, \NoteAddressRand_i,
\item if $\NotePlaintextLeadByte_i \neq \hexint{00}$ or $\NoteCommitmentSprout((\AuthPublic, \Value_i, \NoteAddressRand_i,
\NoteCommitRand_i)) \neq \cm_i$, return $\bot$, else return $\NotePlaintext{i}$.
\end{formulae}
}
@ -5622,15 +5625,14 @@ components of the \noteCiphertext as follows:
\item let $\TransmitPlaintext{} = \SymDecrypt{\TransmitKey{}}(\TransmitCiphertext{})$
\vspace{-0.25ex}
\item if $\TransmitPlaintext{} = \bot$, return $\bot$
\item let $\NotePlaintextLeadByte$ be the first byte of $\TransmitPlaintext{}$
\item extract $\NotePlaintext{} = (\NotePlaintextLeadByte \typecolon \byte, \Diversifier \typecolon \DiversifierType,
\Value \typecolon \ValueType, \NoteCommitRandBytesOrSeedBytes \typecolon \NoteSeedBytesType, \Memo \typecolon \MemoType)$
from $\TransmitPlaintext{}$
\precanopyitem{if $\NotePlaintextLeadByte \neq \hexint{01}$, return $\bot$}
\precanopyitem{extract $\NotePlaintext{} = (\Diversifier \typecolon \DiversifierType, \Value \typecolon \ValueType,
\NoteCommitRandBytes \typecolon \NoteCommitSaplingTrapdoorBytes, \Memo \typecolon \MemoType)$ from $\TransmitPlaintext{}$}
\precanopyitem{let $\NoteCommitRandBytes = \NoteSeedBytes$}
\canopyonwarditem{if $\BlockHeight < \CanopyActivationHeight + \ZIPTwoOneTwoGracePeriod \text{ and } \NotePlaintextLeadByte \not\in \setof{\hexint{01}, \hexint{02}}$, return $\bot$}
\canopyonwarditem{if $\BlockHeight \geq \CanopyActivationHeight + \ZIPTwoOneTwoGracePeriod \text{ and } \NotePlaintextLeadByte \neq \hexint{02}$, return $\bot$}
\vspace{-0.25ex}
\canopyonwarditem{extract $\NotePlaintext{} = (\Diversifier \typecolon \DiversifierType, \Value \typecolon \ValueType,
\NoteSeedBytes \typecolon \NoteSeedBytesType, \Memo \typecolon \MemoType)$ from $\TransmitPlaintext{}$}
\canopyonwarditem{let $\NoteCommitRandBytes = \begin{cases}
\NoteSeedBytes,&\caseif \NotePlaintextLeadByte = \hexint{01} \\
\ToScalar\big(\PRFexpand{\NoteSeedBytes}(\hexarray{05})\kern-0.11em\big),&\caseotherwise
@ -5693,7 +5695,7 @@ and let $\cvField$, $\cmuField$, and $\ephemeralKey$ be those
fields of the \outputDescription (encoding the \valueCommitment, the $u$-coordinate
of the \noteCommitment, and $\EphemeralPublic$).
\introlist
\introsection
\vspace{0.5ex}
The \outgoingViewingKey holder will attempt to decrypt the \noteCiphertext as follows:
@ -5714,15 +5716,14 @@ The \outgoingViewingKey holder will attempt to decrypt the \noteCiphertext as fo
\item let $\TransmitPlaintext{} = \SymDecrypt{\TransmitKey{}}(\TransmitCiphertext{})$
\vspace{-0.25ex}
\item if $\TransmitPlaintext{} = \bot$, return $\bot$
\item let $\NotePlaintextLeadByte$ be the first byte of $\TransmitPlaintext{}$
\item extract $\NotePlaintext{} = (\NotePlaintextLeadByte \typecolon \byte, \Diversifier \typecolon \DiversifierType,
\Value \typecolon \ValueType, \NoteCommitRandBytesOrSeedBytes \typecolon \NoteSeedBytesType, \Memo \typecolon \MemoType)$
from $\TransmitPlaintext{}$
\precanopyitem{if $\NotePlaintextLeadByte \neq \hexint{01}$, return $\bot$}
\precanopyitem{extract $\NotePlaintext{} = (\Diversifier \typecolon \DiversifierType, \Value \typecolon \ValueType,
\NoteCommitRandBytes \typecolon \NoteCommitSaplingTrapdoorBytes, \Memo \typecolon \MemoType)$ from $\TransmitPlaintext{}$}
\precanopyitem{let $\NoteCommitRandBytes = \NoteSeedBytes$}
\canopyonwarditem{if $\BlockHeight < \CanopyActivationHeight + 32256 \text{ and } \NotePlaintextLeadByte \not\in \setof{\hexint{01}, \hexint{02}}$, return $\bot$}
\canopyonwarditem{if $\BlockHeight \geq \CanopyActivationHeight + 32256 \text{ and } \NotePlaintextLeadByte \neq \hexint{02}$, return $\bot$}
\vspace{-0.25ex}
\canopyonwarditem{extract $\NotePlaintext{} = (\Diversifier \typecolon \DiversifierType, \Value \typecolon \ValueType,
\NoteSeedBytes \typecolon \NoteSeedBytesType, \Memo \typecolon \MemoType)$ from $\TransmitPlaintext{}$}
\canopyonwarditem{let $\EphemeralPrivate' = \ToScalar\big(\PRFexpand{\NoteSeedBytes}(\hexarray{04})\kern-0.11em\big)$}
\canopyonwarditem{if $\EphemeralPrivate' \neq \EphemeralPrivate$, return $\bot$}
\canopyonwarditem{let $\NoteCommitRandBytes = \begin{cases}
@ -5745,7 +5746,7 @@ The \outgoingViewingKey holder will attempt to decrypt the \noteCiphertext as fo
\pnote{For a valid \transaction it must be the case that
$\ephemeralKey = \LEBStoOSP{\ellJ}\big(\reprJ\Of{\EphemeralPublic}\kern-0.15em\big)$.}
\canopyonwardnnote{From the step ``let $\NotePlaintextLeadByte$ be the first byte of $\TransmitPlaintext{}$''
\canopyonwardnnote{From the step ``let $\TransmitPlaintext{} = \SymDecrypt{\TransmitKey{}}(\TransmitCiphertext{})$''
onward, this procedure differs from that in \crossref{saplingdecryptivk} only in two ways:
\begin{itemize}
\item in this procedure, the ephemeral \privateKey $\EphemeralPrivate'$ derived from $\NoteSeedBytes$
@ -8165,7 +8166,8 @@ The \notePlaintexts in a \joinSplitDescription are encrypted to the
respective \transmissionKeys $\TransmitPublicNew{\allNew}$.
Each \notsprout{\Sprout} \notePlaintext (denoted $\NotePlaintext{}$) consists of:
\begin{formulae}
\item $(\Value \typecolon \ValueType, \NoteAddressRand \typecolon \PRFOutputSprout,
\item $(\changed{\NotePlaintextLeadByte \typecolon \byte,\ }
\Value \typecolon \ValueType, \NoteAddressRand \typecolon \PRFOutputSprout,
\NoteCommitRand \typecolon \NoteCommitSproutOutput\changed{, \Memo \typecolon \MemoType})$
\end{formulae}
@ -8174,7 +8176,7 @@ The \notePlaintext in each \outputDescription is encrypted to the
\diversifiedTransmissionKey $\DiversifiedTransmitPublic$.
Each \Sapling{} \notePlaintext (denoted $\NotePlaintext{}$) consists of:
\begin{formulae}
\item $(\NotePlaintextLeadByte \typecolon \setof{\hexint{01}\canopy{, \hexint{02}}},
\item $(\NotePlaintextLeadByte \typecolon \byte,
\Diversifier \typecolon \DiversifierType, \Value \typecolon \ValueType,
\NoteCommitRandBytesOrSeedBytes \typecolon \NoteSeedBytesType, \Memo \typecolon \MemoType)$
\end{formulae}
@ -8211,7 +8213,7 @@ The encoding of a \SproutOrNothing{} \notePlaintext consists of:
\begin{equation*}
\begin{bytefield}[bitwidth=0.029em]{1672}
\changed{
\sbitbox{180}{$8$-bit $\hexint{00}$}
\sbitbox{220}{$8$-bit $\NotePlaintextLeadByte$}
&}\sbitbox{180}{$64$-bit $\Value$} &
\sbitbox{256}{$256$-bit $\NoteAddressRand$} &
\sbitbox{256}{\changed{$256$}-bit $\NoteCommitRand$} &
@ -8238,7 +8240,7 @@ The encoding of a \Sapling{} \notePlaintext consists of:
\vspace{1ex}
\begin{equation*}
\begin{bytefield}[bitwidth=0.029em]{1672}
\sbitbox{180}{$8$-bit $\NotePlaintextLeadByte$}
\sbitbox{220}{$8$-bit $\NotePlaintextLeadByte$}
\sbitbox{240}{$88$-bit $\Diversifier$}
\sbitbox{180}{$64$-bit $\Value$}
\sbitbox{256}{$256$-bit $\NoteCommitRandBytesOrSeedBytes$}
@ -8919,8 +8921,9 @@ $\versionField \geq 4$ and $\nShieldedSpend + \nShieldedOutput > 0$.
\overwinteronwarditem{If a \transaction is not a \coinbaseTransaction and its \nExpiryHeight{} field
is nonzero, then it \MUSTNOT be mined at a \blockHeight greater than its \nExpiryHeight.}
\saplingonwarditem{\valueBalance{} \MUST be in the range $\range{-\MAXMONEY}{\MAXMONEY}$.}
\heartwoodonwarditem{All \Sapling outputs in \coinbaseTransactions{} \MUST have valid \noteCommitments
when recovered using a sequence of $32$ zero bytes as the \outgoingViewingKey.}
\heartwoodonwarditem{All \Sapling outputs in \coinbaseTransactions{} \MUST decrypt to a \notePlaintext,
i.e. the procedure in \crossref{saplingdecryptovk} does not return $\bot$, using a sequence of
$32$ zero bytes as the \outgoingViewingKey.}
\item \todo{Other rules inherited from \Bitcoin.}
\end{consensusrules}
@ -10475,6 +10478,12 @@ Peter Newell's illustration of the Jubjub bird, from \cite{Carroll1902}.
\begin{itemize}
\item Delete some `new' superscripts that only added notational clutter.
\item Add an an explicit lead byte field to \Sprout \notePlaintexts, and clearly specify
the error handling when it is invalid.
\sapling{
\item Define \Sapling \notePlaintextLeadBytes as just bytes (so that decoding to a \notePlaintext
always succeeds, and error handling is more explicit).
}
\end{itemize}