Remove viewing keys (except for sk_enc) for now.

Signed-off-by: Daira Hopwood <daira@jacaranda.org>
This commit is contained in:
Daira Hopwood 2016-03-13 02:16:30 +00:00
parent 42954ecdac
commit 10ac791004
4 changed files with 27 additions and 281 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -23,7 +23,7 @@
\setlist[itemize]{itemsep=0.5ex,topsep=0.2ex,after=\vspace{1.5ex}}
\newcommand{\doctitle}{Zcash Protocol Specification}
\newcommand{\docversion}{Version 2.0-draft-3}
\newcommand{\docversion}{Version 2.0-draft-4}
\newcommand{\authors}{Sean Bowe | Daira Hopwood | Taylor Hornby | Nathan Wilcox}
\hypersetup{
@ -55,10 +55,6 @@
\newcommand{\setchanged}{\color{\changedcolor}}
\newcommand{\changed}[1]{\texorpdfstring{{\setchanged{#1}}}{#1}}
\newcommand{\vkcolor}{orange}
\newcommand{\setvk}{\color{\vkcolor}}
\newcommand{\vk}[1]{\texorpdfstring{{\setvk{#1}}}{#1}}
% terminology
\newcommand{\term}[1]{\textsl{#1}\xspace}
@ -137,17 +133,13 @@
% key pairs:
\newcommand{\PaymentAddress}{\mathsf{addr_{pk}}}
\newcommand{\ViewingKey}{\mathsf{addr_{vk}}}
\newcommand{\SpendingKey}{\mathsf{addr_{sk}}}
\newcommand{\PaymentAddressLeadByte}{\hexint{92}}
\newcommand{\ViewingKeyLeadByte}{\hexint{??}}
\newcommand{\SpendingKeyLeadByte}{\hexint{??}}
\newcommand{\CoinCommitmentLeadByte}{\hexint{C0}}
\newcommand{\AuthPublic}{\mathsf{a_{pk}}}
\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}}}}
@ -214,7 +206,6 @@
\newcommand{\SHAOrig}{\term{SHA-256}}
\newcommand{\cm}{\mathsf{cm}}
\newcommand{\cmNew}[1]{\mathsf{{cm}^{new}_\mathnormal{#1}}}
\newcommand{\Trailing}[1]{\mathtt{Trailing}_{#1}}
\newcommand{\ReplacementCharacter}{\textsf{U+FFFD}}
\newcommand{\CryptoBoxSeal}{\mathsf{crypto\_box\_seal}}
@ -292,8 +283,7 @@ payment scheme used by \Bitcoin with a \emph{confidential} payment scheme
protected by zero-knowledge succinct non-interactive arguments of knowledge
(\zkSNARKs).
Changes from the original \Zerocash are highlighted in \changed{\changedcolor},
or in the case of changes for viewing keys, \vk{\vkcolor}.
Changes from the original \Zerocash are highlighted in \changed{\changedcolor}.
\section{Caution}
@ -356,10 +346,6 @@ For example, the diagram
represents the byte sequence $[\hexint{4A}, \hexint{BC}, \hexint{D1}, \hexint{23}]$.
$\Trailing{k}(x)$, where $k$ is an integer, converts the input $x$ to a bit
sequence using big-endian order, and returns the trailing (final) $k$ bits of
that bit sequence.
The notation $\allN{}$, used as a subscript, means the sequence of values
with indices $1$ through $\mathrm{N}$ inclusive. For example,
$\AuthPublicNew{\allNew}$ means the sequence $[\AuthPublicNew{\mathrm{1}},
@ -374,9 +360,9 @@ is used which takes a 512-bit block and produces a 256-bit hash. This is
different from the $\SHAOrig$ function, which hashes arbitrary-length sequences.
\cite{sha256}
$\PRF{x}{}$ is a pseudo-random function seeded by $x$. \changed{Four}/\vk{Five} \emph{independent}
$\PRF{x}{}$ is a pseudo-random function seeded by $x$. \changed{Four} \emph{independent}
$\PRF{x}{}$ are needed in our scheme: $\PRFaddr{x}$, $\PRFsn{x}$, $\PRFpk{x}$\changed{,
$\PRFrho{x}$}\vk{, and $\PRFdk{x}$}.
and $\PRFrho{x}$}.
It is required that $\PRFsn{x}$ \changed{and $\PRFrho{x}$} be collision-resistant
across all $x$ --- i.e. it should not be feasible to find $(x, y) \neq (x', y')$
@ -440,28 +426,13 @@ functions.
\end{bytefield}
\end{lrbox}
\newsavebox{\dkbox}
\begin{lrbox}{\dkbox}
\setvk
\begin{bytefield}[bitwidth=0.06em]{512}
\bitbox{18}{0} &
\bitbox{18}{\iminusone} &
\bitbox{18}{1} &
\bitbox{18}{1} &
\bitbox{224}{252 bit $\DiscloseKey$} &
\bitbox{256}{256 bit $\hSig$}
\end{bytefield}
\end{lrbox}
\begin{equation*}
\begin{aligned}
&\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} \\
\setvk \DerivedKey{i} =\;&\setvk \PRFdk{\DiscloseKey}(i, \hSig)
&\setvk := \CRHbox{\dkbox}
&\setchanged := \CRHbox{\rhobox}
\end{aligned}
\end{equation*}
@ -477,13 +448,12 @@ of the full $\SHAOrig$ hash function -- see \crossref{comm} and \crossref{hsig}.
\section{Concepts}
\subsection{Payment Addresses\vk{, Viewing Keys,} and Spending Keys}
\subsection{Payment Addresses and Spending Keys}
A \keyTuple $(\SpendingKey, \vk{\ViewingKey,\;} \PaymentAddress)$ is
A \keyTuple $(\SpendingKey, \PaymentAddress)$ is
generated by users who wish to receive payments under this scheme.
\vk{The \viewingKey $\ViewingKey$ is derived from the \spendingKey
$\SpendingKey$, and the \paymentAddress $\PaymentAddress$ is derived from
the \viewingKey.}
The \paymentAddress $\PaymentAddress$ is derived from the \spendingKey
$\SpendingKey$.
The following diagram depicts the relations between key components.
Arrows point from a component to any other component(s) that can be derived
@ -493,38 +463,21 @@ from it.
\includegraphics[scale=.8]{key_components}
\end{center}
Note that a \spendingKey holder can derive the other components\vk{,
and a \viewingKey holder can derive $(\AuthPublic, \TransmitPublic)$,}
even though these components are not formally part of the respective keys.
Implementations \MAY cache these derived components, provided that
they are deleted if the corresponding source component is deleted.
The composition of \paymentAddresses\vk{, \viewingKeys,} and \spendingKeys
The composition of \paymentAddresses and \spendingKeys
is a cryptographic protocol detail that should not normally be
exposed to users. However, user-visible operations should be provided
to:
to obtain a \paymentAddress or \viewingKey from a \spendingKey.
\begin{itemize}
\vk{
\item obtain a \paymentAddress from a \viewingKey; and
}
\item obtain a \paymentAddress\vk{ or \viewingKey} from a \spendingKey.
\end{itemize}
\changed{$\AuthPrivate$} \vk{and $\DiscloseKey$} \changed{are each 252 bits.}
\changed{$\AuthPrivate$ is 252 bits.}
$\AuthPublic$, $\TransmitPrivate$, and $\TransmitPublic$, are each 256 bits.
\vk{$\DiscloseKey$,\;}\changed{$\AuthPublic$, $\TransmitPrivate$, and
$\TransmitPublic$ are derived as follows:}
\changed{$\AuthPublic$, $\TransmitPrivate$ and $\TransmitPublic$ are derived
as follows:}
{\hfuzz=50pt
\begin{equation*}
\begin{aligned}
\vk{\DiscloseKey} &\vk{\;:= \Trailing{252}(\PRFaddr{\AuthPrivate}(0))} & \\
\AuthPublic &:= \vbox{$\begin{cases}
\vk{\PRFaddr{\DiscloseKey}(1)} & \text{\vk{with viewing keys}} \\
\changed{\PRFaddr{\AuthPrivate}(3)} & \text{\changed{without viewing keys}}
\end{cases}$} & \\
\TransmitPrivate &:= \changed{\Clamp(\PRFaddr{\AuthPrivate}(2))} & \\
\AuthPublic &:= \changed{\PRFaddr{\AuthPrivate}(0)} \\
\TransmitPrivate &:= \changed{\Clamp(\PRFaddr{\AuthPrivate}(1))} \\
\TransmitPublic &:= \changed{\CurveMultiply(\TransmitPrivate, \CurveBase)}
\end{aligned}
\end{equation*}
@ -776,19 +729,13 @@ $\scriptPubKey$.
\item $\commitments$ which is a $\NNew$ size sequence of \coinCommitments
$\cmNew{\allNew}$.
\changed{
\item $\ephemeralKey$ which is a Curve25519 public key $\EphemeralPublic$.
\item $\encCiphertexts$ which is a $\NNew$ size sequence of ciphertext
components, $\TransmitCiphertext{\allNew}$.
}
\vk{
\item $\discloseCiphertexts$ which is a $\NOld$ size sequence of ciphertext
components, $\DiscloseCiphertext{\allOld}$.
}
\setchanged{
(The preceding fields starting from $\ephemeralKey$ together form the \coinsCiphertext.)
\changed{
(The preceding two fields form the \coinsCiphertext.)
\item $\randomSeed$ which is a random 256-bit seed $\RandomSeed$.
}
@ -869,17 +816,14 @@ A valid instance of $\PourProof$ assures that given a \term{primary input}:
\begin{itemize}
\item[] $(\rt, \snOld{\allOld}, \cmNew{\allNew}, \changed{\vpubOld,\;}
\vpubNew, \hSig, \h{\allOld}, \vk{\TransmitCiphertext{\allNew},
\DiscloseCiphertext{\allOld}})$,
\vpubNew, \hSig, \h{\allOld})$,
\end{itemize}
there exists a witness of \term{auxiliary input}:
\begin{itemize}
\item[] $(\treepath{\allOld}, \cOld{\allOld}, \AuthPrivateOld{\allOld},
\changed{\cpNew{\allNew}, \CoinAddressPreRand,\;}
\vk{\DiscloseKeyOld{\allOld}, \TransmitKey{\allNew}, \DerivedKey{\allOld},
\TransmitPublicNew{\allNew}, \EphemeralPrivate})$
\cpNew{\allNew}\changed{, \CoinAddressPreRand})$
\end{itemize}
where:
@ -887,12 +831,8 @@ where:
\begin{itemize}
\item[] for each $i \in \setofOld$: $\cOld{i} = (\AuthPublicOld{i},
\vOld{i}, \CoinAddressRandOld{i}, \CoinCommitRandOld{i})$;
\item[] for each $i \in \setofNew$: $\begin{cases}
\cpNew{i} = (\AuthPublicNew{i},
\vNew{i}, \CoinAddressRandNew{i}, \CoinCommitRandNew{i}, \Memo_i) \\
\TransmitPlaintext{i} \text{ is an encoding of } \cpNew{i}
\text{ per \crossref{coinpt};}
\end{cases}$
\item[] for each $i \in \setofNew$: $\cNew{i} = (\AuthPublicNew{i},
\vNew{i}, \CoinAddressRandNew{i}, \CoinCommitRandNew{i})$
\end{itemize}
such that the following conditions hold:
@ -914,17 +854,8 @@ $\snOld{i} = \PRFsn{\AuthPrivateOld{i}}(\CoinAddressRandOld{i})$.
\subparagraph{Spend authority}
{\hfuzz=200pt
for each $i \in \setofOld$:
\raisebox{-5ex}{\vbox{$
\begin{aligned}
\vk{\DiscloseKeyOld{i}} &\vk{\;= \Trailing{252}(\PRFaddr{\AuthPrivateOld{i}}(0))} \\
\AuthPublicOld{i} &= \vbox{$\begin{cases}
\vk{\PRFaddr{\DiscloseKeyOld{i}}(1)} & \text{\vk{with viewing keys}} \\
\changed{\PRFaddr{\AuthPrivateOld{i}}(3)} & \text{\changed{without viewing keys.}}
\end{cases}$}
\end{aligned}
$}}{\hbadness=10001 \par}}
$\AuthPublicOld{i} = \changed{\PRFaddr{\AuthPrivateOld{i}}(0)}$.
\subparagraph{Non-malleability}
@ -942,64 +873,6 @@ $\CoinAddressRandNew{i} = \PRFrho{\CoinAddressPreRand}(i, \hSig)$.
for each $i \in \setofNew$: $\cmNew{i}$ = $\CoinCommitment(\cNew{i})$.
\vk{
\subparagraph{$\TransmitCiphertext{}$ integrity}
for each $i \in \setofNew$:
$\TransmitCiphertext{i} = \SymEncrypt{\TransmitKey{i}}(\TransmitPlaintext{i})$.
}
\newsavebox{\sharedbox}
\begin{lrbox}{\sharedbox}
\setvk
\begin{bytefield}[bitwidth=0.052em]{768}
\bitbox{256}{\hfill\; 256 bit $\TransmitKey{\mathrm{1}}$ \hfill ...\;} &
\bitbox{256}{256 bit $\TransmitKey{\NNew}$} &
\bitbox{120}{64 bit $\vOld{\mathrm{1}}$ ...} &
\bitbox{120}{64 bit $\vOld{\NOld}$} \\
\bitbox{256}{\hfill\; 256 bit $\TransmitPublicNew{\mathrm{1}}$ \hfill ...\;} &
\bitbox{256}{256 bit $\TransmitPublicNew{\NNew}$} &
\bitbox{256}{256 bit $\EphemeralPrivate$}
\end{bytefield}
\end{lrbox}
\newsavebox{\disclosebox}
\begin{lrbox}{\disclosebox}
\setvk
\begin{bytefield}[bitwidth=0.052em]{256}
\bitbox{256}{256 bit $\DerivedKey{\mathrm{1}}$} &
\end{bytefield}
\end{lrbox}
\newsavebox{\plaintextbox}
\begin{lrbox}{\plaintextbox}
\setvk
\vbox{
$\DisclosePlaintext{1} := \Justthebox{\sharedbox}{-5.5ex}$
$\DisclosePlaintext{i} := \Justthebox{\disclosebox}{-1.3ex}$ for $i \in \setof{2..\NOld}$.
}
\end{lrbox}
\vk{
\subparagraph{$\DiscloseCiphertext{}$ integrity}
for each $i \in \setofOld$:
$\DiscloseCiphertext{i} = \SymEncrypt{\DerivedKey{i}}(\DisclosePlaintext{i})$
and $\DerivedKey{i} = \PRFdk{\DiscloseKeyOld{i}}(i, \hSig)$
}
\vk{\hfuzz=50pt
where \Justthebox{\plaintextbox}{-9.95ex}
\subparagraph{Note:}
$\TransmitPublicNew{\allNew}$, $\EphemeralPrivate$, and
$\Memo_{\allNew}$ are intentionally not constrained. This
implies that for the $\TransmitCiphertext{}$ and $\DiscloseCiphertext{}$
integrity constraints, the circuit need not compute $\SymCipher$ blocks
that are only used to encrypt those fields (although the $\SymAuth$
authenticator must be computed over the whole of each ciphertext).
}
\section{In-band secret distribution} \label{inband}
@ -1011,10 +884,6 @@ 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}.
\vk{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}
@ -1051,10 +920,8 @@ Define $\KDF(\DHSecret{i}, \EphemeralPublic, \TransmitPublicNew{i}, i) :=$
}
Let $\TransmitPublicNew{\allNew}$ be the \changed{Curve25519} public keys
for the intended recipient addresses of each new \coin,
\vk{let $\DiscloseKeyOld{\allOld}$ be the \discloseKey for each of
the addresses from which the old \coins are sent,} and let $\CoinPlaintext{\allNew}$
be the \coinPlaintexts.
for the intended recipient addresses of each new \coin, and let
$\CoinPlaintext{\allNew}$ be the \coinPlaintexts.
Then to encrypt:
\begin{itemize}
@ -1072,16 +939,10 @@ $(\EphemeralPublic, \EphemeralPrivate)$.
\SymEncrypt{\TransmitKey{i}}(\TransmitPlaintext{i})$.
\end{itemize}
}
\vk{\hfuzz=50pt
\item For $i \in \setofOld$, let $\DerivedKey{i} := \PRFdk{\DiscloseKeyOld{i}}(i, \hSig)$.
\item Let \Justthebox{\plaintextbox}{-9.95ex}
\item For $i \in \setofOld$,
let $\DiscloseCiphertext{i} := \SymEncrypt{\DerivedKey{i}}(\DisclosePlaintext{i})$.
}
\end{itemize}
The resulting \coinsCiphertext is $\changed{(\EphemeralPublic,
\TransmitCiphertext{\allNew}}\vk{, \DiscloseCiphertext{\allOld}}\changed{)}$.
\TransmitCiphertext{\allNew})}$.
\subsection{Decryption by a Recipient}
@ -1124,67 +985,6 @@ as transactions are added to that view. Also, blockchain reorganisations may cau
the transaction in which a coin was output to no longer be on the consensus
blockchain.
\vk{
\subsection{Decryption by a Viewing Key Holder}
}
\vk{
A \viewingKey holder also acts as a recipient using its $\TransmitPrivate$ key
component. How to decrypt transactions using this key component is described in
the preceding section. The following applies to decryption using the $\DiscloseKey{}$
component of the \viewingKey.
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:
\begin{enumerate}
\item For $i \in \setofOld$,
\begin{itemize}
\item Let $\DerivedKey{i} := \PRFdk{\DiscloseKey{}}(i, \hSig)$.
\item Let $\DisclosePlaintext{i} := \SymDecrypt{\DerivedKey{i}}(\DiscloseCiphertext{i})$.
\end{itemize}
\item Let $k$ be the index of the first non-$\bot$ value in $\DisclosePlaintext{\allOld}$,
or $\bot$ if there is no such value.
\item Let $\SharedPlaintext := \begin{cases}
\bot, & \text{if $k = \bot$} \\
\DisclosePlaintext{1}, & \text{if $k = 1$} \\
\SymDecrypt{\DisclosePlaintext{k}}(\DiscloseCiphertext{1}), & \text{otherwise.}
\end{cases}$
\item If $\SharedPlaintext = \bot$ then
set $\vOld{i} = \bot$ for $i \in \setofOld$ and
$\CoinPlaintext{i} = \bot$ for $i \in \setofNew$, and return
$(\vOld{\allOld}, \CoinPlaintext{\allNew})$.
\item Extract $\TransmitKey{\allNew}$, $\vOld{\allOld}$,
$\TransmitPublicNew{\allNew}$, and $\EphemeralPrivate$ from $\SharedPlaintext$.
\item For $i \in \setofNew$,
\begin{itemize}
\item Let $\CoinPlaintext{i} :=
\DecryptCoin(\TransmitKey{i}, \TransmitCiphertext{i}, \cmNew{i})$.
\item Let $\EphemeralPrivateClamped := \Clamp(\EphemeralPrivate)$.
\item Let $\EphemeralPublicCompare := \CurveMultiply(\EphemeralPrivateClamped, \CurveBase)$.
\item Let $\DHSecretCompare{i} := \CurveMultiply(\EphemeralPrivateClamped, \TransmitPublicNew{i})$.
\item Let $\TransmitKeyCompare{i} := \KDF(\DHSecretCompare{i}, \EphemeralPublicCompare,
\TransmitPublicNew{i}, i)$.
\item If $\CoinPlaintext{i} \neq \bot$ and either
($\TransmitKeyCompare{i} \neq \TransmitKey{i}$ or
$\EphemeralPublicCompare \neq \EphemeralPublic$), then set the \memo
of $\CoinPlaintext{i}$ to be $\bot$ (indicating that, although this is a valid
coin, the recipient cannot be proven to be able to decrypt it, and that the \memo
cannot be verified).
\end{itemize}
\item Return $(\vOld{\allOld}, \CoinPlaintext{\allNew})$.
\end{enumerate}
\subparagraph{Note:}
The above algorithm is not constant-time. An equivalent but constant-time algorithm
should be used whenever it is desirable to avoid leakage of which ciphertext
components were decryptable.
If a party holds more than one \viewingKey, it may optimize the above
procedure by performing the loop in step 1 for the $\DiscloseKey{}$ of each
\viewingKey, and assuming that only one key could correctly decrypt each
$\DiscloseCiphertext{}$.
}
\changed{
\subsection{Commentary}
@ -1202,25 +1002,12 @@ Note that:
public keys of both parties, and the index $i$.
\item The nonce parameter to $\SymSpecific$ is not used.
}
\vk{
\item The ephemeral secret $\EphemeralPrivate$ is included together with
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
output coins; instead, those are symmetrically encrypted to the
\viewingKey and the correctness of this encryption is checked by the
\PourCircuit.)
}
\end{itemize}
\section{Encoding Addresses and Keys}
This section describes how \Zcash encodes \paymentAddresses, \spendingKeys\vk{,
and \viewingKeys}.
This section describes how \Zcash encodes \paymentAddresses and \spendingKeys.
Addresses and keys can be encoded as a byte sequence; this is called
the \term{raw encoding}. This byte sequence can then be further encoded using
@ -1305,44 +1092,6 @@ and produces a suitable Base58Check leading character.}
\nathan{what about the network version byte?}
\vk{
\subsection{Viewing Keys}
}
\vk{
A \viewingKey consists of a \discloseKey $\DiscloseKey$, and a
\transmitKeypair private key $\TransmitPrivate$.
The raw encoding of a \viewingKey consists of, in order:
}
\begin{equation*}
\begin{bytefield}[bitwidth=0.07em]{520}
\setvk
\bitbox{72}{8 bit $\ViewingKeyLeadByte$} &
\bitbox{32}{$\zeros{4}$} &
\bitbox{252}{252 bit $\DiscloseKey$}
\bitbox{256}{256 bit $\TransmitPrivate$}
\end{bytefield}
\end{equation*}
\vk{
\begin{itemize}
\item A byte $\ViewingKeyLeadByte$ indicating this version of the
raw encoding of a \Zcash \viewingKey.
\item 4 zero padding bits.
\item 252 bits specifying $\DiscloseKey$.
\item 256 bits specifying $\TransmitPrivate$.
\end{itemize}
Note that, consistent with big-endian encoding, the zero padding occupies
the high-order 4 bits of the second byte.
\daira{check that this lead byte is distinct from other Bitcoin stuff,
and produces a suitable Base58Check leading character.}
\nathan{what about the network version byte?}
}
\section{Differences from the Zerocash paper}
@ -1557,9 +1306,6 @@ the \Zerocash protocol design; in addition to the inventors, this includes
Mike Perry, Isis Lovecruft, Leif Ryge, Andrew Miller, Zooko Wilcox,
Samantha Hulsey, and no doubt others.
Mike Perry, Zooko Wilcox, and Nathan Wilcox contributed to the design
of selective transparency features, now called viewing keys.
The Faerie Gold attack was found by Zooko Wilcox.
The internal hash collision attack was found by Taylor Hornby.