Author

Topic: [ESHOP launched] Trezor: Bitcoin hardware wallet - page 259. (Read 965789 times)

member
Activity: 78
Merit: 10
Chris Chua
And this is the main problem. You need whole raw transaction in the memory to calculate sha256 for tx_hash. And size of raw tx is growing lineary with number of inputs.
I wasn't very clear on the description of my method, but every hash can be calculated without having any transaction entirely in RAM.

I "found" following algorithm:

1. Client sends SignTx message with the list of outputs to the device.
2. Device displays outputs and amounts on the display, waiting for confirmation by the user.
3. Client start sending TxInput messages. For N inputs, client send N^2+N messages, like in this pseudocode:

Code:
inputs = [] # list of TxInput
for i in inputs:
    for x in inputs:
        send(x) # Sends TxInput to the device
        
    signature = send(SignInput(i)) # Ask for input signature after X inputs

Thanks to this and thanks to streaming capabilities of SHA256, it is possible to check inputs and build tx_hash without a need to store raw transaction in device memory at all. There's some minor overhead in the API and the API don't looks so nice because it resends TxInputs over and over, but memory footprint is extremely low.
You can go even further than this. If you send the entire serialised spending transaction once for each TxInput, you don't even need to store outputs. You can then have essentially unlimited inputs and outputs.
legendary
Activity: 1386
Merit: 1097
3. The spending transaction is serialised as it would be in OP_CHECKSIG (with all inputs removed except for the signing input, which has its script replaced).

And this is the main problem. You need whole raw transaction in the memory to calculate sha256 for tx_hash. And size of raw tx is growing lineary with number of inputs.

I "found" following algorithm:

1. Client sends SignTx message with the list of outputs to the device.
2. Device displays outputs and amounts on the display, waiting for confirmation by the user.
3. Client start sending TxInput messages. For N inputs, client send N^2+N messages, like in this pseudocode:

Code:
inputs = [] # list of TxInput
for i in inputs:
    for x in inputs:
        send(x) # Sends TxInput to the device
        
    signature = send(SignInput(i)) # Ask for input signature after X inputs

Thanks to this and thanks to streaming capabilities of SHA256, it is possible to check inputs and build tx_hash without a need to store raw transaction in device memory at all. There's some minor overhead in the API and the API don't looks so nice because it resends TxInputs over and over, but memory footprint is extremely low.
member
Activity: 78
Merit: 10
Chris Chua
This is definitely interesting topic to think about. I think the device will have some known hard limit of inputs and outputs, depending on used chip and amount of available RAM. This information can be provided over the API (message Features?), so desktop client will have a chance to handle it properly (offer to split transaction to more smaller ones, for example).

But maybe we find some algorithm how to do signing in some streaming way so the device won't need to have everything loaded into the memory at a time...

FWIW, here's approximately the method I use:
1. Supporting transactions (i.e. transactions whose outputs are being spent) precede the spending transaction in the data stream.
2. Supporting transactions are serialised as they would be in the blockchain.
3. The spending transaction is serialised as it would be in OP_CHECKSIG (with all inputs removed except for the signing input, which has its script replaced).
4. Before each supporting transaction, the output number of the output being spent is explicitly specified.

This allows the bunch of supporting and spending transactions to be parsed by a streaming parser. Each output in the spending transaction can be displayed and approved as it is parsed.

The supporting transactions are there to calculate the transaction fee. The parser does this to calculate the transaction fee:
1. For each supporting transaction, the hash of the transaction, tx_hash, is calculated.
2. For each supporting transaction, the nominated output (from (4) above) has its amount added to the transaction fee.
3. The list of tx_hash and output numbers is itself hashed into ref_hash_compare.
4. When the parser sees the spending transaction, it takes the list of input reference transaction hashes and input reference numbers and hashes them into ref_hash. ref_hash should == ref_hash_compare. This step is necessary to confirm that the correct supporting transactions are being included.
5. For each output in the spending transaction, the output amount is subtracted from the transaction fee.

BIP 0010 is relevant to this discussion. What do you think of BIP 0010? It might be a good idea to talk to etotheipi about it, if you haven't already.
legendary
Activity: 1386
Merit: 1097
But maybe we find some algorithm how to do signing in some streaming way so the device won't need to have everything loaded into the memory at a time...

I think that we just found a solution for unlimited number of inputs and very high limit of outputs. I'll update protocol specification soon...
legendary
Activity: 1386
Merit: 1097
This is definitely interesting topic to think about. I think the device will have some known hard limit of inputs and outputs, depending on used chip and amount of available RAM. This information can be provided over the API (message Features?), so desktop client will have a chance to handle it properly (offer to split transaction to more smaller ones, for example).

But maybe we find some algorithm how to do signing in some streaming way so the device won't need to have everything loaded into the memory at a time...
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
Also, I just mentioned this to someone42 via PM, but I want to throw it up here -- I recently got a bug report because someone was having issues signing a transaction that had 483 inputs !?!  The transaction itself was 120 kB, and the supporting transactions to be transferred to the offline system was a couple megabytes.  I hadn't really realized that such huge transactions were "feasibly likely", and it might be worth thinking about how to deal with that situation.  If you can handle signing 500 inputs and the RAM and bandwidth to push that much data around -- great.  On the other hand, some transactions just shouldn't be possible (500 kB+ won't ever be accepted by the network).  Maybe it's more of a software issue to prevent that... but I wanted to throw it out there as a corner case that should be considered.

It was probably someone with many pool payouts. I think he spent huge amounts on tx fees :-). I don't think such big transaction would go thru the device because of RAM consumption. However I don't have any estimation about limits of current design yet.

Yes, there were other problems with the transaction beyond simply accumulating signatures.  But the point is, it would be nice if things didn't just fail cryptically, or if it could be avoided altogether.   The avoidance solution is more of a software thing, but perhaps the device should recognize when its own limits are about to be exceeded.

And, in posting about this in another thread, multiple users mentioned that they were likely to run into the same situation.  I bet businesses will run into it a lot -- your offline wallet is really intended for collecting, not spending.  A lot of people will collect money to the offline wallet for months before they decide they want to do something with the money.   And, if a business uses offline wallets to serve their 500 customers per day, then they'll be trying to execute one of these transactions each day!   Or a much larger one once a week.  I've been thinking about making a special warning message in Armory for this, with recommendations about splitting it into multiple transactions... but I haven't acted on it yet. 
legendary
Activity: 1386
Merit: 1097
Also, I just mentioned this to someone42 via PM, but I want to throw it up here -- I recently got a bug report because someone was having issues signing a transaction that had 483 inputs !?!  The transaction itself was 120 kB, and the supporting transactions to be transferred to the offline system was a couple megabytes.  I hadn't really realized that such huge transactions were "feasibly likely", and it might be worth thinking about how to deal with that situation.  If you can handle signing 500 inputs and the RAM and bandwidth to push that much data around -- great.  On the other hand, some transactions just shouldn't be possible (500 kB+ won't ever be accepted by the network).  Maybe it's more of a software issue to prevent that... but I wanted to throw it out there as a corner case that should be considered.

It was probably someone with many pool payouts. I think he spent huge amounts on tx fees :-). I don't think such big transaction would go thru the device because of RAM consumption. However I don't have any estimation about limits of current design yet.
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
I recommend the hardware switch because you don't want to make it too easy to overwrite the current master seed in the device.  In fact, you don't want malicious software on your desktop to be able to issue the overwrite request without your permission.  Having a user confirmation perhaps solves this, but does make it subject to user error, and especially dangerous for users that don't back up their seeds.

It the most paranoid settings, you'll have to confirm any action like this by pressing hardware button and then entering OTP and password (PIN) to the desktop client. I think this is much safer and error prone than some magic hw switch on the device. At least UX will be the same for every case.

Fair enough.  It's actually more consistent your way, anyway.  I was just concerned about users plugging in their device and having the key maliciously overwritten, but it sounds like you got that covered.



Also, I just mentioned this to someone42 via PM, but I want to throw it up here -- I recently got a bug report because someone was having issues signing a transaction that had 483 inputs !?!  The transaction itself was 120 kB, and the supporting transactions to be transferred to the offline system was a couple megabytes.  I hadn't really realized that such huge transactions were "feasibly likely", and it might be worth thinking about how to deal with that situation.  If you can handle signing 500 inputs and the RAM and bandwidth to push that much data around -- great.  On the other hand, some transactions just shouldn't be possible (500 kB+ won't ever be accepted by the network).  Maybe it's more of a software issue to prevent that... but I wanted to throw it out there as a corner case that should be considered.
legendary
Activity: 1386
Merit: 1097
If the user resets the device and then plugs it in again, I need to create a new MultiBit wallet for them using the new seed (and ignore the old wallet I guess). If they have, say, written on it,  "Lifetime savings" they could put this in the wallet description. It would be a different wallet file on their system though as all the addresses/ tx etc are different.

I see. In this case, identifying the wallet by master private key is the way to go.
legendary
Activity: 1386
Merit: 1097
I recommend the hardware switch because you don't want to make it too easy to overwrite the current master seed in the device.  In fact, you don't want malicious software on your desktop to be able to issue the overwrite request without your permission.  Having a user confirmation perhaps solves this, but does make it subject to user error, and especially dangerous for users that don't back up their seeds.

It the most paranoid settings, you'll have to confirm any action like this by pressing hardware button and then entering OTP and password (PIN) to the desktop client. I think this is much safer and error prone than some magic hw switch on the device. At least UX will be the same for every case.

Quote
However, in my own thought-experiments, I thought it was a good idea not to even allow access to the public key through the device (or maybe provide an option to not store it).

Master private key can be generated from the seed at any time. So there's no way how to *not* store it on the device.

Hiding the master private key will annoy regular users for most of the time, BUT don't provide any additional real security measure. If you're the attacker who already have physical access to the device and to the computer (keylogger for the PIN), you'll probably try to steal coins in any case. If you won't have such access, the information about the master public key won't help you much. Although, have an option to confirm GetMasterPublicKey message by pressing the button may be added for extra paranoid users.
legendary
Activity: 1708
Merit: 1066
Hi Slush,

If the user resets the device and then plugs it in again, I need to create a new MultiBit wallet for them using the new seed (and ignore the old wallet I guess). If they have, say, written on it,  "Lifetime savings" they could put this in the wallet description. It would be a different wallet file on their system though as all the addresses/ tx etc are different.

Jim
legendary
Activity: 1386
Merit: 1097
The UUID on the protobuf is for the device I believe. Is there always only a single wallet on the device ?

UUID is generated from processor serial number, so it will mostly identify the token itself than seed/key loaded in the memory.

Quote
Do I need to check the MasterPublicKey ie if the device is reset will its UUID change ?

UUID don't change between device resets. You can choose if you prefer to identify the seed (using master private key) or the physical device (using UUID).

In my opinion it's better to identify the physical device. It may be less confusing to still have the token with the same name ("Lifetime savings") than see unknown token when I reload it with the new seed.
legendary
Activity: 1708
Merit: 1066
Cheers Alan,
That looks the way to go.

Would be good for it to be in BIP32, if for no other reason than to have the same wallet name for the same device on different clients. I'll put a note in the doc I am writing about it.
legendary
Activity: 1428
Merit: 1093
Core Armory Developer
Although "downloading" the seed from the device into the computer won't be possible, there'll be a way how to upload custom seed from attached computer. There won't be any need for special hardware switch on the device, it just displays request if you want to rewrite current seed by that provided by the computer.

I recommend the hardware switch because you don't want to make it too easy to overwrite the current master seed in the device.  In fact, you don't want malicious software on your desktop to be able to issue the overwrite request without your permission.  Having a user confirmation perhaps solves this, but does make it subject to user error, and especially dangerous for users that don't back up their seeds.   Personally, I would prefer a HW switch and maybe even require a screwdriver to get to the switch, since it will be used so infrequently...  but I can understand not wanting to do it.  Just more food for thought.


Device will handle just the master private key and it will derive every address from it. It won't allow you to handle private keys for custom address. This is limitation which will make the interface much easier.

...

Device will just provide master public key to the computer and then it will be just able to sign for addresses derived from this master key.

Yeah, I was inelegant in my phrasing, and that's exactly what I was suggesting -- no custom addresses, and only pulling off the master public key.  I wasn't sure if you were allowing the public key to be accessible from the device

However, in my own thought-experiments, I thought it was a good idea not to even allow access to the public key through the device (or maybe provide an option to not store it).  The reason is -- if it's actually really difficult to get the private key off the device, and the thief doesn't actually know how much money is protected by the device, they have a lot less incentive to try to break it.   If the public key is accessible, they know exactly what their reward will be breaking it.  But there's a lot of versatility advantages to letting it spit out the master public key...


legendary
Activity: 1428
Merit: 1093
Core Armory Developer
I am writing up some proposed improvements to MultiBit wallet handling and have a couple of questions.

I want to create a unique MultiBit wallet name for the device when it is plugged in and for that wallet name to be the same if the user plugs it in again sometime later.

The UUID on the protobuf is for the device I believe. Is there always only a single wallet on the device ?
What I mean is: as long as the MasterPublicKey has not changed (i.e. device has not been reset) and the UUID is the same, then it is the same wallet ?

Do I need to check the MasterPublicKey ie if the device is reset will its UUID change ?


FYI, I've been meaning to talk to sipa about unique wallet identifiers, but haven't yet.  In the current incarnation of Armory wallets, I had used a combination of the root address and the first address after it to create a mostly-unique 6-byte ID for the wallet.  This was so that a given combination of root seed and chaining algorithm would have unique IDs.  Chaining algorithm doesn't have to be part of it with standardized BIP 32 (maybe just food for thought)... but I think it is appropriate to add an identifier scheme which would solve your problem.

legendary
Activity: 1708
Merit: 1066
I am writing up some proposed improvements to MultiBit wallet handling and have a couple of questions.

I want to create a unique MultiBit wallet name for the device when it is plugged in and for that wallet name to be the same if the user plugs it in again sometime later.

The UUID on the protobuf is for the device I believe. Is there always only a single wallet on the device ?
What I mean is: as long as the MasterPublicKey has not changed (i.e. device has not been reset) and the UUID is the same, then it is the same wallet ?

Do I need to check the MasterPublicKey ie if the device is reset will its UUID change ?

edit: maybe I should just use the MasterPublicKey to name the MultiBit wallet.





legendary
Activity: 1708
Merit: 1066
That made me laugh out loud.

With the limited resources we all have in Bitcoinland, I think of everything as more of a marathon than a sprint.

You can feel people consolidating around BIP32 / HD wallets so I think they are the best bet to concentrate on.
You'll be able to get it all working initially with Electrum wallets so I don't think it is going to be rate limiting for you.

It is just less work to support just the two formats.
legendary
Activity: 1386
Merit: 1097
I expect by the time your hardware wallet is production ready everybody will have implemented BIP32 wallets.

Jim, I hope your implementation is making progress quickly ;-).
legendary
Activity: 1386
Merit: 1097
About the protocol itself - we're implementing generic class HID device, which has some benefits (like no need for driver installation). The wire protocol itself is Google's Protocol Buffers, providing perfect message-oriented serialization, which can generate bindings for every major platform (C/C++, Java, .NET, Python).

Current draft of protobuf messages (still under construction) is here: https://github.com/slush0/bitkey-python/blob/master/bitkey_proto/bitkey.proto I'm not sure how easy is to understand high level purpose of the protocol just from protobuf specs, but I'll provide some comments soon.

Currently I'm working on device emulator in Python, which will be also used for that Raspberry Pi version. When I'll have some working prototype, I'll demonstrate it's capabilities and I'll open the discussion about decision which I made. However I want to have some working code to talk about, instead of theoretical discussion about "what features should such token have".
legendary
Activity: 1386
Merit: 1097
It is possible that this platform will be standard design for BTC hardware wallets in the future. Better, at least, take in account the possibility to add security and plan some reliability for the platform, like batter battery backup, option to backup one wallet to a new one, option to add 3G modem, etc.
Look at most used software wallet.

Adding battery backup and 3G modem is far over current project goals. But as far as the communication protocol isn't tied with the implementation, it will be definitely possible to build 3G+battery powered devices, compatible with current device.
Jump to: