These aren’t new, they’re just new to me, and I think they’re really neat. Like most non-revolutionary technology, they solve a problem that wouldn’t have existed without the larger scope of that very same technology.
Here’s a look at how they might be applied to a usecase with which I’m very familiar: cloud-based, brick-and-mortar point of sale.
Background
I spent a bunch of years working at Shopkeep, so I have some familiarity with the technical problems and architectures around accepting credit payments. Making a payment to a merchant with a credit card is essentially saying “here is the ability to take as much money from me as you’d like. Please only take the amount we’ve agreed upon.” And there are layers of obfuscation, regulation, delay, and escrow to hide that fundamental truth. Accepting payment in Bitcoin offers a completely different set of tradeoffs, which are definitely appealing to some merchants.
Here are a few approaches for integrating Bitcoin payments into a product like Shopkeep:
1. The Naive Approach
- Get a single address from a merchant
- Ship that down to the register and use it for all payments
- Use math to guess which payment on the blockchain corresponds to each transaction the merchant made.
This option sucks. It eschews the best practice of using a new address for each payment (this has security implications), and it introduces an unnecessarily hard problem. In my experience, people who are paying for software expect it to work perfectly. This will never work perfectly. For example, if Andrew and Matthew both show up to a coffee shop and pay for similar drinks, but only one payment shows up on the blockchain for that amount, the merchant will never know which of them is the deadbeat.
2. The Easy Approach
- Build it completely as an integration to someone else like Coinbase
Third-party trust adds an element of risk, and Coinbase is not without fees. Mostly though, this option is just kinda lame. If I owned an existing cloud-based point of sale company with tens of thousands of customers, this is what I would do, but it’s definitely not neat. And I probably wouldn’t write a blog post like this about it.
3. The Over-Architected Clusterfuck
- On an air-gapped machine, generate thousands of private keys and their corresponding addresses.
- Move the addresses to an online datastore.
- Assign a bunch of addresses to each merchant. Ship down 100 or so to each register for use. Make sure they always have fresh, never-used addresses for accepting new payments.
- Monitor the blockchain for all of these addresses. As we see bitcoins showing up, report on them to the correct merchants.
- Allow merchants to “withdraw” whenever they like by uploading a new address. We batch transactions and send their bitcoins to them on whatever schedule they prefer.
This approach has two huge drawbacks: 1) enormous complexity, and 2) holding private keys. The complexity is really so much that it feels like a completely different business model (which in fact, it is), so we’d probably screw up a lot. And there are big risks with touching private keys at all. We just want to facilitate the acceptance of payments, not have access to anything sensitive.
Ideally, there would be a solution that:
- enables a unique bitcoin receiving address for each and every payment
- does not require centralized management of any private keys at all
- does not require trusting any third parties
Enter Hierarchical Deterministic Wallets
BIP 32 describes a standard for creating keys that can deterministically create more keys in a tree-like structure. Here’s what an extended private key looks like:
xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7
From that XPRV, we can create its corresponding extended public key, which is this:
xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw
And from that XPUB, we can get the corresponding receiving address (indistinguishable from an address generated any other way):
19Q2WoS5hSS6T8GjhK8KZLMgmWaq4neXrh
From the XPRV, we can also get the private key which is necessary for actually spending anything received at the above address:
5KcyH2JHhyVEJZ6VnmKHbWYEK7KeQzkEKeZQ62qcNfgkELdEdGB
And here is one of its thousands of potential child XPRVs:
xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs
With the parent extended key, we don’t need to store the children, because they can always be recalculated. For a point-of-sale-system, it means we would only need to store one XPRV for each merchant which is a dramatic simplification to our solution. But we’re still storing a private key, which is a really bad idea.
Get Ready For The Neat
It turns out elliptic curve cryptography is really neat, and there’s a way to walk the tree and create all of the necessary addresses for a merchant without needing any XPRVs at all. You can do it with just the root XPUB. And it’s almost exactly the same process. Say wat?! My momma always taught me that it was mathematically infeasible to make a public key from anything but the corresponding private key. Momma wasn’t really giving me the whole truth.
So, here’s some scribbles that show generating child nodes starting from the XPRV and from the XPUB:
All of this and more can be found here: github.com/xgess/xpub_stuff
This means it’s possible for a merchant to give a point of sale system nothing but an XPUB. The system can generate addresses on the fly, and no one but the merchant will be able to spend those funds. Here’s what our solution looks like now!
4. Not-So-Over-Architected
- Get a merchant’s XPUB from a traditionally secure web form (these are exportable from most wallets).
- Design a scheme for hierarchy based on locations and registers. Send the appropriate children XPUBs to the merchant’s registers.
- Each register generates a new payment address per transaction at the time of the sale, all of which are traceable and organized hierarchically.
We are no longer storing private keys of any kind, all reporting is deterministic, the merchant immediately has access to all of their funds, and all technical problems are tractable. How cool is that?!
Other Stuff
- XPUBs are not without any risk at all. If a private key leaks, you can use an XPUB to identify sibling private keys. That’s not good, but the risk for this usecase is minimal since the private keys stay with the merchant at all times.
- I didn’t talk at all about `hardened` extended keys. They are an important part of any good hierarchical key management system. Like all good crypto-tradeoffs, you gain some security and lose some features.
- Over the last year, Bitcoin’s utility for on-chain transactions has changed quite a bit, and I’m actually not sure yet if/how hierarchical keys might work in a layer-2-lightning world. Regardless, they’re still phenomenally useful for anyone or any organization that would like to have multiple addresses.
- Here are the full deets on the actual BIP 32 specification: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
Sonja Biemer says
You sure know what you’re talking about. Everyone is going to soon be visiting your site.