Slight updates to libraries, Christianization of sox_accounting.
26 KiB
lang | title |
---|---|
en | Wallet Implementation |
The primary function of the wallet file is to provide a secret key for a public key, though eventually we stuff all sorts of user odds and ends into it.
In Bitcoin, this is simply a pile of random secrets, randomly generated, but obviously it is frequently useful to have them not random, but merely seemingly random to outsiders. One important and valuable application of this is the paper wallet, where one can recreate the wallet from its master secret, because all the seemingly random secret keys are derived from a single master secret. But this does not cover all use cases.
We care very much about the case where a big important peer in a big central node of the internet, and the owner skips out with the paper key that owns the peer’s reputation in his pocket, and sets up the same peer in another jurisdiction, and everyone else talks to the peer in the new jurisdiction, and ignores everything the government seized.
The primary design principle of our wallet is to bypass the DNS and ICANN, so that people can arrange transactions securely. The big security hole in Bitcoin is not the one that Monero fixes, but that you generally arrange transactions on the totally insecure internet. The spies care about the metadata more than they care about the data. We need to internalize and secure the metadata.
We particularly want peers to be controlled by easily hidden and transported secrets. The key design point around which all else is arranged is that if some man owns a big peer on the blockchain, and the cops descend upon it, he grabs a book of his bookshelf that looks like any airport book, except on pencil in the margins of one page is his master secret, written in pencil, and a list of all his nicknames, also written in pencil. Then he skips off to the airport and sets up his peer on a new host, and no one notices that it has moved except for the cops who grabbed his now useless hardware. (Because the secrets on that hardware were only valuable because their public keys were signed by his keys, and when he starts up the new hardware, his keys will sign some new keys on the peer and on the slave wallet on that hardware.)
We also want perfect forward secrecy, which is easy. Each new connection initiation starts with a random transient public key, and any identifying information is encrypted in the shared secret formed from that transient public key, and the durable public key of the recipient.
We also want off the record messaging. So we want to prove to the recipient that the sender knows the shared secret formed from the recipients public key and the sender’s transient private key, and also the shared secret formed from the recipient’s public key, the sender’s transient private key, and the sender’s durable private key. But the recipient, though he then knows the message came from someone who has the sender’s durable private key, cannot prove that to a third party, because he could have constructed that shared secret, even if the sender did not know it. The recipient could have forged the message and sent it to himself.
Thus we get off the record messaging. The sender by proving knowledge of two shared secrets, proves to the recipient knowledge of two secret keys corresponding to the two public keys provided, but though the sender proves it to the recipient, the recipient cannot prove it to anyone else.
The message consists of transient public key in the clear, which encrypts durable public key. then durable public key plus transient public key encrypts the rest of the message, which encryption proves knowledge of the secret key underlying the durable public key, proves it to the recipient, but he cannot prove it to anyone else.
The durable public key may be followed by the schema identifier 2, which implies the nickname follows, which implies the twofitytwo bit hash of the public key followed by nickname, which is the global identifier of the pseudonym sending the message. But we could have a different schema, 3, corresponding to a chain of signatures authenticating that public key, subject to timeouts and indications of authority, which we will use in slave wallets and identifiers that correspond to a corporate role in a large organization, or in iff applications where new keys are frequently issued.
If we have a chain of signatures, the hash is of the root public key and the data being signed (names, roles, times, and authorities) but not the signatures themselves, nor the public keys that are being connected to that data.
When someone initiates a connection using such a complex identity, he sends proof of shared knowledge of two shared secrets, and possibly a chain of signatures, but does not sign anything with the transient public key, nor the durable public key at the end of the chain of signatures, unless, as with a review, he wants the message to be shared around, in which case he signs the portion of the message that is to be shared around with that public key, but not the part of the message that is private between sender and receiver.
To identify the globally unique twofitytwo bit id, the recipient hashes the public key and the identifier that follows. Or he may already know, because the sender has a client relationship with the recipient, that the public key is associated with a given nickname and globally unique identifier.
If we send the schema identifier 0, we are not sending id information, either because the recipient already has it, or because we don’t care, or because we are only using this durable public key with this server and do not want a global identity that can be shared between different recipients.
So, each master wallet will contain a strong human readable and human writeable master secret, and the private key of each nickname will be generated by hashing the nickname with the master secret, so that when, in some new location, he types in the code on fresh hardware and blank software, he will get the nickname’s public and private keys unchanged, even if he has to buy or rent all fresh hardware, and is not carrying so much as a thumbdrive with him.
People with high value secrets will likely use slave wallets, which perform functions analogous to a POP or IMAP server, with high value secrets on their master wallet, which chats to their slave wallet, which does not have high value secrets. It has a signed message from the master wallet authorizing it to receive value in the master wallets name, and another separately signed message containing the obfuscation shared secret, which is based on the master wallet secret and an,the first integer being the number of the transaction with the largest transaction in that name known to the master wallet, an integer that the slave wallet increments with every request for value. The master wallet needs to provide a name for the slave wallet, and to recover payments, needs that name. The payments are made to a public key of the master wallet, multiplied by a pseudo random scalar constructed from the hash of a sequential integer with an obfuscation secret supplied by the master wallet, so that the master wallet can recover the payments without further communication, and so that the person making the payment knows that any payment can only be respent by someone who has the master wallet secret key, which may itself be the key at the end of chain of signatures identity, which the master wallet posesses, but the slave wallet does not.
For slave wallets to exist, the globally unique id has to be not a public key, but rather the twofiftytwo bit hash of a rule identifying the public key. The simplest case being hash(2|public key|name), which is the identifier used by a master wallet. A slave wallet would use the identifier hash(3|master public key|chain of signed ids) with the signatures and public keys in the chain omitted from the hash, so the durable public key and master secret of the slave wallet does not need to be very durable at all. It can, and probably should, have a short timeout and be frequently updated by messages from the master wallet.
The intent is that a slave wallet can arrange payments on behalf of an identity whose secret it does not possess, and the payer can prove that he made the payment to that identity. So if the government grabs the slave wallet, which is located in a big internet data center, thus eminently grabbable, it grabs nothing, not reputation, not an identity, and not money. The slave wallet has the short lived and regularly changed secret for the public key of an unchanging identity identity authorized to make offers on behalf a long lived identity, but not the secret for an identity authorized to receive money on behalf of a long lived identity. The computer readable name of these identities is a twofiftytwo bit hash, and the human readable name is something like receivables@_@globally_unique_human_readable_name, or sales@_@globally_unique_human_readable_name. The master secret for _@globally_unique_human_readable_name is closely held, and the master secret for globally_unique_human_readable_name written in pencil on a closely held piece of paper and is seldom in any computer at all.
For a name that is not globally unique, the human readable name is non_unique_human_readable_nickname zero_or_more_whitespace 42_characters_of_slash6_code zero_or_more_whitespace.
Supposing Carol wants to talk to Dave, and the base point is B. Carols secret is the scalar c
, and her public key is elliptic point C=c*B
. Similarly Dave’s secret is the scalar d
, and his public key is elliptic point
D=d*B
.
His secret scalar d
is probably derived from the hash of his master secret with his nickname, which we presume is "Dave".
They could establish a shared secret by Carol calculating c*D
, and
Dave calculating d*C
. But if either party’s key is seized, their
past communications become decryptable. Plus this unnecessarily leaks metadata
o people watching the interaction.
Better, Carol generates a random scalar r
, unpredictable to anyone
else, calculates R=r*B
, and sends Dave R, C
encrypted
using r*D,
and the rest of the message encrypted using (r+c)*D
.
This gives us perfect forward secrecy and off-the-record.
One flaw in this is that if Dave’s secret leaks, not only can he and the people communicating with him be spied upon, but he can receive falsified messages that appear to come from trusted associates.
One fix for this is the following protocol. When Carol initiates communication with Dave, she encrypts only with the transient public and private keys, but when Dave replies, he encrypts with another transient key. If Carol can receive his reply, it really is Carol. This does not work with one way messages, mail like messages, but every message that is a reply should automatically contain a reference to the message that it replies to, and every message should return an ack, so one way communication is a limited case.
Which case can be eliminated by handling one way messages as followed up by mutual acks. For TCP, the minimum set up and tear down of a TCP connection needs three messages to set up a connection, and three messages to shut it down, so if we could multiplex encryption setup into communication setup, which we should, we could bullet proof authentication. To leak the least metadata, want to establish keys as early in the process as we can while avoiding the possibility of DNS attacks against the connection setup process. If communication only ensues when both sides know four shared secrets, then the communication can only be forged or intercepted by a party that knows both sides durable secrets.
We assume on public key per network address and port – that when she got the port associated with the public key, she learned what which of his possibly numerous public keys will be listening on that port.
Carol calculates (c+r)*D
. Dave calculates d*(C+R)
, to arrive at a shared secret, used only once.
That is assuming Carol needs to identify. If this is just a random anonymous client connection, in which Dave responds the same way to every client, all she needs to send is R
and D
. She does not need forward secrecy, since not re-using R
. But chances are Dave does not like this, since chances are he wants to generate a record of the distinct entities applying, so a better solution is for Carol to use as her public key when talking to Dave hash(c, D)*B
Sometimes we are going to onion routing, where the general form of an onion routed message is [R, D,
encrypted] with the encryption key being d*R = r*D
. And inside that encryption may be another message of the same form, another layer of the onion.
But this means that Dave cannot contact Carol. But maybe Carol does not want to be contacted, in which case we need a flag to indicate that this is an uncontactable public key. Conversely, if she does want to be contactable, but her network address changes erratically, she may need to include contact info, a stable server that holds her most recent network address.
Likely all she needs is that Dave knows that she is the same entity as logged in with Dave before. (Perhaps because all he cares about is that this is the same entity that paid Dave for services to be rendered, whom he expects to keep on paying him for services he continues to render.)
The common practical situation, of course is that Carol@Name wants to talk to Dave@AnotherName, and Name knows the address of AnotherName, and AnotherName knows the name of Dave, and Carol wants to talk to Dave as Carol@Name. To make this secure, have to have have a a commitment to the keys of Carol@Name and Dave@AnotherName, so that Dave and Carol can see that Name and AnotherName are showing the same keys to everyone.
The situation we would like to have is a web of public documents rendered immutable by being linked into the blockchain, identifying keys, and a method of contacting the entity holding the key, the method of contacting the identity holding the key being widely available public data.
In this case, Carol may well have a public key only for use with Name, and Dave a public key only for use with AnotherName.
If using d*C
as the identifier, inadvisable to use a widely known C
, because this opens attacks via d
, so C
should be a per host public key that Carol keeps secret.
The trouble with all these conversations is that they leak metadata – it is visible to third parties that C
is talking to D
.
Suppose it is obvious that you are talking to Dave, because you had to look up Dave’s network address, but you do not want third parties to know that Carol is talking to Dave. Assume that Dave’s public key is the only public key associated with this network address.
We would rather not make it too easy for the authorities to see the public key of the entity you are contacting, so would like to have D end to end encrypted in the message. You are probably contacting the target through a rendevous server, so you contact the server on its encrypted key, and it sets up the rendevous talking to the wallet you want to contact on its encrypted key, in which case the messages you send in the clear do not need, and should not have, the public key of the target.
Carol sends R
to Dave in the clear, and encrypts C
and r
*D
, using the shared secret key r
*D
= d
*R
Subsequent communications take place on the shared secret key (c+r)*D = d*(C+R)
Suppose there are potentially many public keys associated with this network address, as is likely to be the case if it is a slave wallet performing Pop and Imap like functions. Then it has one primary public key for initiating communications. Call its low value primary keys p and P. Then Carol sends R
in the clear, followed by D
encrypted to r*P = p*R
, followed by C
and r*D
, encrypted to r*D = d*R
.
We can do this recursively, and Dave can return another, possibly transient, public key or public key chain that works like a network address. This implies a messaging system whose api is that you send an arbitrary length message with a public key as address, and possibly a public key as authority, and an event identifier, and then eventually you get an event call back, which may indicate merely that the message has gone through, or not, and may contain a reply message. The messaging system handles the path and the cached shared secrets. All shared secrets are in user space, and messages with different source authentication have different connections and different shared secrets.
Bitcoin just generates a key at random when you need one, and records it. A paper wallet is apt to generate a stack of them in advance. They offer the option of encrypting the keys with a lesser secret, but the master secret has to be stronger, because it has to be strong enough to resist attacks on the public keys.
On reflection, there are situations where this is difficult – we would like the customer, rather than the recipients, to generate the obfuscation keys, and pay the money to a public key that consists of the recipients deeply held secret, and a not very deeply held obfuscation shared secret.
This capability is redundant, because we also plan to attach to the transaction a Merkle hash that is the root of tree of Merkle hashes indexed by output, in Merkle-patricia order, each of which may be a random number or may identify arbitrary information, which could include any signed statements as to what the obligations the recipient of the payment has agreed to, plus information identifying the recipient of the payment, in that the signing key of the output is s*B+recipient_public key. But it would be nice to make s derived from the hash of the recipients offer, since this proves that when he spends the output, he spends value connected to obligations.
Such receipts are likely generated by a slave wallet, which may well do things differently to a master wallet. So let us just think about the master wallet at this point. We want the minimum capability to do only those things a master wallet can do, while still being future compatible with all the other things we want to do.
When we generate a public key and use it, want to generate records of to how it was generated, why, and how it was used. But this is additional tables, and an identifier in the table of public keys saying which additional table to look at.
One meaning per public key. If we use the public key of a name for many purposes, use it as a name. We don’t use it as a transaction key except for transactions selling, buying, or assigning that name. But we could have several possible generation methods for a single meaning.
And, likely, the generation method depends on the meaning. So, in the table of public keys we have a single small integer telling us the kind of thing the public key is used for, and if you look up that table indicated by the integer, maybe all the keys in that table are generated by one method, or maybe several methods, and we have a single small integer identifying the method, and we look up the key in that table which describes how to generate the key by that method.
Initially we have only use. Names. And the table for names can have only one method, hence does not need an index identifying the method.
So, a table of public key private key pairs, with a small integer identifying the use and whether the private key has been zeroed out, and a table of names, with the rowid of the public key. Later we introduce more uses, more possible values for the use key, more tables for the uses, and more tables for the generation methods.
A wallet is the data of a Zooko identity. When logged onto the interent is is a Zooko triangle identity or Zookos quandrangle identity, but is capable of logging onto the internet as a single short user identity term, or logging on with one peer identity per host. When that wallet is logged in, it is Zooko identity with its master secret and an unlimited pile of secrets and keys generated on demand from a single master secret.
We will want to implement the capability to receive value into a key that is not currently available. So how are we going to handle the identity that the wallet will present?
Well, keys that have a time limited signature that they can be used for certain purposes in the name of another key are a different usage, that will have other tables, that we can add later.
A receive only wallet, when engaging in a transaction, identifies itself as Zooko identity for which it does not have the master key, merely a signed authorization allowing it to operate for that public key for some limited lifetime, and when receiving value, requests that value be placed in public keys that it does not currently possess, in the form of a scalar and the public key that will receive the value. The public key of the transaction output will be s*B+D
, where s is the obfuscating value that hides the beneficiery from the public blockchain, B is the base, and D
is the beneficiary. B is public, s*B+D
is public, but s and D
are known only to the parties to the transaction, unless they make them public.
And that is another usage, and another rule for generating secrets, which we can get around to another day.
The implementation can and will vary from one peer to the next. The canonical form is going to be a Merkle-patricia dac, but the Merkle-patricia dac has to be implemented on top of something, and our first implementation is going to implement the Merkle-patricia dac on top of a particular sqlite database with a particular name, and that name stored in a location global to all programs of a particular user on a particular machine, and thus that database global to all programs of that particular user on that particular machine.
Then we will implement a global consensus Merkle-patricia dac, so that everyone agrees on the one true mapping between human readable names, but the global consensus dac has to exist on top of particular implementations run by particular users on particular machines, whose implementation may well vary from one machine to the next.
A patricia tree contains, in itself, just a pile of bitstreams. To represent actual information, there has to be a schema. It has to be a representation of something equivalent to a pile of records in a pile of database tables. And so, before we represent data, before we create the patricia tree, have to first have a particular working database, a particular implementation, which represents actual data. Particular database first, then we construct universal canonical representation of that data second.
In every release version, starting with the very first release, we are going to have to install a database, if one is not already present, in order that the user can communicate with other users, so we will have no automagic creation of the database. I will manually create and install the first database, and will have a dump file for doing so, assuming that the dump file can create blobs.
A receive only wallet contains the public key and zooko name of its master wallet, optionally a thirty two byte secret, a numbered signed record by the master wallet authorizing it to use that name and receive value on the master wallet secret and its own public key.
A zooko quandrangle identifier consists of a public master key, a globally accepted human readable name globally accepted as identifying that key, a local human readable petname, normally identical to the global name, and an owner selected human readable nickname.
A contact consists of a public key, and network address information where you will likely find a person or program that knows the corresponding private key, or is authorized by that private key to deal with communications.
So, first thing we have to do is create a wxWidgets program that accesses the database, and have it create Zooko’s triangle identities, with the potential for becoming Zooko’s quandrangle identities.
Proving knowledge of the secret key of a public key
Our protocol, unlike bitcoin, has proof of transaction. The proof is private, but can be made public, to support ebay type reputations.
Supposing you are sending value to someone, who has a big important reputation that he would not want damaged. And you want proof he got the value, and that he agreed to goods, services, or payment of some other form of money in return for the value.
Well, if he has a big important reputation, chances are you are not transacting with him personally and individually through a computer located behind a locked door in his basement, to which only he has the key, plus he has a shotgun on the wall near where he keeps the key. Rather, you are transacting with him through a computer somwhere in the cloud, in a big computing center to which far too many people have access, including the computer center management, police, the Russian mafia, the Russian spy agency, and the man who mops the floors.
So, when "he", which is to say the computer in the cloud, sends you public keys for you to put value into on the blockchain, you want to be sure that only he can control value you put into the blockchain. And you want to be able to prove it, but you do not want anyone else except you and he (and maybe everyone who has access to the data center on the cloud) can prove it except you make the data about your transaction public.
You are interacting with a program. And the program probably only has low value keys. It has a key signed by a key signed by a key signed by his high value and closely held key, with start times and timeouts on all of the intermediate keys.
So he should have a key that is not located in the datacenter, and you want proof that only the holder of that key can spend the money – maybe an intermediate key with a timeout on it that authorizes it to receive money, which signs an end key that authorizes the program to agree to deals, but not to receive money – the intermediate key authorized to receive money presumably not being in the highly insecure data center.
This document is licensed under the CreativeCommons Attribution-Share Alike 3.0 License{rel="license"}