Pages:
Author

Topic: Deterministic wallets - page 4. (Read 48264 times)

member
Activity: 104
Merit: 10
May 13, 2013, 12:00:35 PM
If we have P_i=HMAC(I_L,P)*G+P they can't do that.

Did you mean P_i=HMAC(HMAC(secret),P)*G+P and reveal HMAC(secret) for the linkage proof, as you suggested in post #228 ?
So the company wouldn't be able to workaround the issue with Q:=P+r*G because they couldn't compute an x such that P_i==HMAC(x,Q)*G+Q ?

Yes, that's exactly what I meant. You can either use the I_L as it was before, from I:=HMAC(chaincode,P||i), and plug that into P_i:=HMAC(I_L,P)*G+P,
or redefine I_L := HMAC(HMAC(chaincode,i),P) and do P_i:=I_L*G + P, as you like.
sr. member
Activity: 360
Merit: 251
May 13, 2013, 08:49:49 AM
If we have P_i=HMAC(I_L,P)*G+P they can't do that.

Did you mean P_i=HMAC(HMAC(secret),P)*G+P and reveal HMAC(secret) for the linkage proof, as you suggested in post #228 ?
So the company wouldn't be able to workaround the issue with Q:=P+r*G because they couldn't compute an x such that P_i==HMAC(x,Q)*G+Q ?
member
Activity: 104
Merit: 10
May 13, 2013, 06:29:24 AM
1. Can we reserve more than one bit of the number i for different kind of derivations, not only the highest bit? This would allow addition other kinds of derivations or tweaks of existing ones in the future.

Adding more flag bits is certainly possible, but we can extend the length of the serialized i value in that case, so the only thing that needs to change is the serialization format.

Do you mean to change the serialization format even for the two derivations that we have now? Like add another byte?

If smartcards have a problem with SHA512, they'll have a huge problem with ECDSA.

Ok.

And third, can you change
Code:
I = HMAC( cpar, Kpar || i)
in the public derivation to
Code:
I = HMAC( HMAC(cpar,i),  Kpar)
? I see the provability of the link as a quite an important property (cf. #228).

That provability argument is interesting, but can you come up with use cases?

iddo and you asked about use cases. Say a company has two departments A and B that have publicly known pubkeys P (for A) and Q (for B). They receive incoming payments on derived keys P_i and Q_i. At the end of the fiscal year the company wants to prove their balance sheet to an auditor. They want to prove to the auditor that A had this amount of income, and B that amount of income. I am assuming they don't want to give the chaincodes to the auditor. So for each i they tell the auditor the multipliers I_L such that P_i=I_L*G+P, and also the multipliers such that Q_i=I_L*G+Q. Right? No! The company can set up P and Q from the beginning so that they can decide at the end of the fiscal year to which department they like to associate each individual incoming payment. Dividing the incomes however they like between A and B, as long as they don't exceed the total sum of course. If we have P_i=HMAC(I_L,P)*G+P they can't do that.

The "setup" works like this: The company picks P and r and sets Q:=P+r*G. Say P_i = I_L*G+P. If they want to associate P_i to P they give the auditor I_L, if they want to associate P_i to Q they give the auditor I_L-r instead (never both, of course, because then they blow up).
sr. member
Activity: 360
Merit: 251
May 12, 2013, 02:54:21 PM
How does it depend on the choice of hash function?
I guess this is something purely theoretical, right?

It's not related to hash functions, it's a generic proof of computation.
Not purely theoretical, there's a compiler in relatively early stages that's already working. For computation of a specific hash function, major optimizations could be done.
But let's not hijack this thread with unrelated matters, please PM me if you'd like.
legendary
Activity: 1072
Merit: 1174
May 12, 2013, 02:38:13 PM
1. Can we reserve more than one bit of the number i for different kind of derivations, not only the highest bit? This would allow addition other kinds of derivations or tweaks of existing ones in the future.

Adding more flag bits is certainly possible, but we can extend the length of the serialized i value in that case, so the only thing that needs to change is the serialization format.

5. It is certainly possible to do everything with HMAC-SHA256 alone. For instance, if you need two values like (I_L,I_R) you can do I_L=HMAC(secret,0) and I_L=HMAC(secret,1). The question is, does it reduce dependencies of the code, code review, etc. to be worthwhile?

All this might get implemented on smardcards one day. I really don't understand why you'd want to rely on a new, second hash function here, SHA512. Entropy is _not_ a reason.

I like the simplicity of a single existing construct that operates natively on 512 bits. Yes, separate SHA256 calls would work too, but are less elegant IMHO. I don't mean to say it would be less secure, and this is just bike shedding.

If smartcards have a problem with SHA512, they'll have a huge problem with ECDSA.

Quote
And third, can you change
Code:
I = HMAC( cpar, Kpar || i)
in the public derivation to
Code:
I = HMAC( HMAC(cpar,i),  Kpar)
? I see the provability of the link as a quite an important property (cf. #228).

BTW, the function I will propose for payer-derived payment addresses (which is basically just a deterministic wallet of the payee in the hands of the payer) will be
Code:
K_derived := HMAC( m, K_base) *G + K_base
where m is the (hash of the) invoice or contract that is being paid for.
This would fit nicely together, as it would be the exact same function just with m substituted for HMAC(cpar,i). We could re-use code as well as security reasoning.

That provability argument is interesting, but can you come up with use cases? I'm also interested in knowing the complexity of iddo's zero-knowledge proofs that could avoid this.
member
Activity: 104
Merit: 10
May 12, 2013, 12:36:42 PM
How does it depend on the choice of hash function?
I guess this is something purely theoretical, right?
sr. member
Activity: 360
Merit: 251
May 12, 2013, 12:19:35 PM
You can prove that you know c_par such that both (I_L,I_R)=hash(c_par, K_par, i) and K_i=I_L*K_par, without revealing c_par itself, via zero-knowledge computational integrity (PCP) proofs.

Really, you can zero-knowledge prove that you know a preimage of a hash?

Yes, you don't send the entire proof (this wouldn't be ZK and the proof is long anyway), you just let the verifier query a few bits from the proof, and if you didn't know the preimage then the verifier will catch you w.h.p.

Edit: actually you can send a very short full proof by building a Merkle tree from blocks of the long PCP proof and using the Merkle root as seed for pseudorandom queries, see SNARKs for more info.
member
Activity: 104
Merit: 10
May 12, 2013, 11:55:20 AM
You can prove that you know c_par such that both (I_L,I_R)=hash(c_par, K_par, i) and K_i=I_L*K_par, without revealing c_par itself, via zero-knowledge computational integrity (PCP) proofs.

Really, you can zero-knowledge prove that you know a preimage of a hash?
sr. member
Activity: 360
Merit: 251
May 12, 2013, 10:40:32 AM
I found an argument why the multiplier I_L in K_i := I_L *Kpar (or k_i := I_L*G + Kpar) should depend on Kpar.

Recall: In BIP 32 we have (IL,IR) = func(cpar,Kpar,i) whereas I previously had suggested (IL,IR) = func(cpar,i).

The argument is about the provability of the link between Kpar and K_i. There are three things that one might want to prove:
1. Kpar and Ki have the same owner
2. Ki was derived from Kpar (and not some other parent)
3. Kpar existed before Ki

Revealing I_L clearly proves 1. So let's discuss the other two properties.
Case IL=func(cpar,i): Given Ki we can choose arbitrary cpar and i, compute I_L:=func(cpar,i), compute Kpar with Ki=I_L*Kpar. So we can trivially come up with infinitely many plausible parents Kpar.
Case IL=func(cpar,Kpar,i): The above is not possible anymore, at least if Kpar is properly hashed in func. If we know Kpar we can check that it is a parent, otherwise we cannot come up with any plausible parent at all. So we can prove 2. and 3. after all.

For this to be useful, as we might not want to reveal cpar, we would define:
I_L := func(func(cpar,i),Kpar)
and reveal func(cpar,i) as proof of the link. So I actually suggest (for type-2):
Code:
I := HMAC( HMAC(cpar,i) , Kpar)

What would be some possible use cases for your (2) and (3) here?
You can prove that you know c_par such that both (I_L,I_R)=hash(c_par, K_par, i) and K_i=I_L*K_par, without revealing c_par itself, via zero-knowledge computational integrity (PCP) proofs. There will be a talk about it by my PhD supervisor in the upcoming Bitcoin conference (unfortunately I cannot attend the conference).
So we could achieve your goals with (significantly) more complexity which would be used only when needed, instead of pushing this hash(hash()) extra complexity on everyone.
sr. member
Activity: 360
Merit: 251
May 12, 2013, 09:51:04 AM
BTW, there has not been a compelling argument for making I_L in type-2 depend on Kpar either. IMO this just closes a door, is completely unnecessary, and even complicates reasoning about the security of the whole scheme.

I offered you some arguments with regard to reduced security and privacy in post #218, and Pieter and I mentioned that you'd feed less than optimal entropy into the hash function (e.g. you'd repeatedly feed 256 pseudorandom bits to derive the next 512 pseudorandom bits, instead of 512-->512 as in BIP32). One reason why you might not find the entropy argument compelling is that you don't spell out your exact proposal on how to do type-2 and type-1 derivations. I'm not sure if you think that the chaincode should depend on the parent privkey with type-1 derivation.
member
Activity: 104
Merit: 10
May 12, 2013, 09:05:05 AM
BTW, there has not been a compelling argument for making I_L in type-2 depend on Kpar either. IMO this just closes a door, is completely unnecessary, and even complicates reasoning about the security of the whole scheme. But ok, let it be as it is and close that discussion now, as time pressurizes before the conference.

Pieter, can you please address these three points:
  
1. Can we reserve more than one bit of the number i for different kind of derivations, not only the highest bit? This would allow addition other kinds of derivations or tweaks of existing ones in the future.

5. It is certainly possible to do everything with HMAC-SHA256 alone. For instance, if you need two values like (I_L,I_R) you can do I_L=HMAC(secret,0) and I_L=HMAC(secret,1). The question is, does it reduce dependencies of the code, code review, etc. to be worthwhile?

All this might get implemented on smardcards one day. I really don't understand why you'd want to rely on a new, second hash function here, SHA512. Entropy is _not_ a reason.

And third, can you change
Code:
I = HMAC( cpar, Kpar || i)
in the public derivation to
Code:
I = HMAC( HMAC(cpar,i),  Kpar)
? I see the provability of the link as a quite an important property (cf. #228).

BTW, the function I will propose for payer-derived payment addresses (which is basically just a deterministic wallet of the payee in the hands of the payer) will be
Code:
K_derived := HMAC( m, K_base) *G + K_base
where m is the (hash of the) invoice or contract that is being paid for.
This would fit nicely together, as it would be the exact same function just with m substituted for HMAC(cpar,i). We could re-use code as well as security reasoning.
legendary
Activity: 1072
Merit: 1174
May 12, 2013, 05:41:27 AM
I still haven't seen a compelling argument for being able to change chaincode independently of keys. As far as I'm concerned, they constitute an somewhat-less-secret overflow entropy buffer for keys, and are thus intimately linked with them.

Yes, I understand there are use cases, but they seem far-fetched and either assume it is hard to set up a secure communication channel between trusted parties (which I think in practice is easy), or integrating them more tightly into multisig schemes (which I don't like; scripts/addresses are a layer strictly above key derivation, imho; in that sense I also dislike using the term "address" for identifying keys - it should only be called address when you're talking about the script template associated with a particular key, with the intention of receiving coins on it).

Maybe at some point there will be a use case important enough, and we can still standardize a system for "updating" a BIP32 chain with a new chaincode, though I don't like the complexity of reasoning about the security of that.

Unless someone comes up with a use case that it worth supporting (and hopefully doesn't require pretty much rewriting it from scratch...), I'm going to announce the current specification as final on the conference next week.
member
Activity: 104
Merit: 10
May 12, 2013, 05:26:29 AM
Btw, it is my intention with Armory to do exactly what you just said is out of scope.  There's no reason to optimize the case of multiple wallets coming from the same seed, because most of the time you don't ever want a single device seeing all the keys.  You want your phone to create one key, your computer to create another key, completely independently.  In the case of a big organization, you want different branches to create their wallets independently, and swap pubkey-chaincode pairs.  

Exactly: swap chaincodes. If they swap their chaincodes anyway they could just as well use the exact same one. (It doesn't make a difference securitywise if they do.)

Plus, if there's, say, a vulnerability in one of the devices' RNG, you'd prefer that it only affect one piece of the multisig wallet.

That's an argument, indeed. Plus, a party may not want to rely on another party's entropy but prefer to use it's own.

There's a lot of possibilities there.  While there may some use cases where keys are generated on the same device, that's far from guaranteed.  In fact, I think it's the opposite, if we want to promote security best practices.

Yes, lot's of different ways. I'm just saying prepare for the fact that chaincodes will get re-used across different pubkeys. Whether it's for multisigs or some other purpose. Even if it's not the default behaviour for multisigs and even if you don't promote it in any other way, people might still find applications for it and do it. Chaincodes are only semi-secret after all.

legendary
Activity: 1428
Merit: 1093
Core Armory Developer
May 11, 2013, 05:54:40 PM
My impression was you wanted to stay as close as possible with current key/address handling and in particular wanted a map addr -> chaincode. The easiest multisig generalization (in terms of handling) would be one chaincode per multisig address. Matter of taste I guess.

Individual chaincodes per pubkey in a multisig can do potentially more, like combining different pubkeys from unrelated chains into a multisig. But that's far beyond scope of BIP 32 I assume. With one chaincode per address there is no handling issues and you can trivially implement derivation from a multisig address with very few additional lines of code.

Btw, it is my intention with Armory to do exactly what you just said is out of scope.  There's no reason to optimize the case of multiple wallets coming from the same seed, because most of the time you don't ever want a single device seeing all the keys.  You want your phone to create one key, your computer to create another key, completely independently.  In the case of a big organization, you want different branches to create their wallets independently, and swap pubkey-chaincode pairs.  They need to do that to guarantee that no one employee ever has access to all the pieces.  And that all the pieces are never geographically co-located. 

Plus, if there's, say, a vulnerability in one of the devices' RNG, you'd prefer that it only affect one piece of the multisig wallet. 

There's a lot of possibilities there.  While there may some use cases where keys are generated on the same device, that's far from guaranteed.  In fact, I think it's the opposite, if we want to promote security best practices.
member
Activity: 104
Merit: 10
May 11, 2013, 01:44:39 PM
- get the basescript with GetCScript(id)

Where does the CScript from if you don't know the other keys in the first place? P2SH transactions do not contain the actual (public) keys anyway, so whatever you do, you need some metadata about the P2SH script in your wallet. I don't see the problem with extending this with the individual BIP32 public parent keys (if you need to be able to access the entire chain of multisig addresses in the first place).

I mean you do have the other keys, of course, inside the CScript. But that doesn't necessarily mean that the other keys are present as entries of their own in the key database. HasKey() will still return false for the ids of the individual pubkeys of the script, unless you imported them individually.

My impression was you wanted to stay as close as possible with current key/address handling and in particular wanted a map addr -> chaincode. The easiest multisig generalization (in terms of handling) would be one chaincode per multisig address. Matter of taste I guess.

Individual chaincodes per pubkey in a multisig can do potentially more, like combining different pubkeys from unrelated chains into a multisig. But that's far beyond scope of BIP 32 I assume. With one chaincode per address there is no handling issues and you can trivially implement derivation from a multisig address with very few additional lines of code.
sr. member
Activity: 360
Merit: 251
May 10, 2013, 09:59:28 PM
If you consider hierarchies of multisig addresses this turns into an argument why c_i should not depend on Kpar. Because if the parent is a multisig address, which of the pubkeys should c_i depend on? I say let c_i not depend on any of them. Then you can split your pubkeys across several machines and still derive arbitrary many levels on each machine, even if not all pubkeys of the multisig address are present on the machine.

I don't understand, if some pubkeys aren't present, then what exactly do you claim that you could do now, which you couldn't do if c_i depends on K_par ? If there's a single chaincodes tree, you still cannot derive a new child pubkey if its parent pubkey isn't present. Sync'ing the multisig keys just according to the derivation indices makes more sense as far as I can see.
This appears to be once again an argument for gaining efficiency in exchange for potential loss of security, and in the context of multisig the security concerns are more pronounced, because the whole point of having separate keys on different machines that control an address once they are combined is that the data that's stored on a single machine isn't enough to steal the coins, and now you're proposing that the chaincode data will be shared across the separate machines, just for (dubious?) gains in efficiency?
Even if it's a good idea, you haven't shown how to support a single chaincode tree when type-1 derivations are allowed.
legendary
Activity: 1072
Merit: 1174
May 10, 2013, 07:30:41 PM
- get the basescript with GetCScript(id)

Where does the CScript from if you don't know the other keys in the first place? P2SH transactions do not contain the actual (public) keys anyway, so whatever you do, you need some metadata about the P2SH script in your wallet. I don't see the problem with extending this with the individual BIP32 public parent keys (if you need to be able to access the entire chain of multisig addresses in the first place).
member
Activity: 104
Merit: 10
May 10, 2013, 10:46:27 AM
I imagined constructing multisig addresses of a set of (potentially completely independent) BIP32 chains, using equal indices in each, in lockstep.

In my opinion, BIP32 is mostly about generating sequences of keys, which can either be used directly as pay-to-pubkeyhash addresses, or combined using multisig into a P2SH address. Isn't that both more simple than trying to put BIP32 on top of multisig, and no reason for having the chaincodes be independent?

I thought to derive like this from a multisig given by a CScriptID called id:
- get the basescript with GetCScript(id)
- extract the pubkeys with Solver()
- get the chaincode by calling a new function GetCChaincode(id)
- call CKD() for each pubkey
- put together with SetMultisig()
- store with AddCScript()

As you describe it, you would have to keep track of several chaincodes or run another lookup at the third line. What if some of the individual pubkeys are simply not present in pwalletMain? Maybe they aren't on some of your machines. Just seems like more to take track of this way.

Of course, combining pubkeys from arbitrary chains into a multisig is somewhat more flexible. But deriving from multisig scripts may be more straight forward than we thought. Individual pubkeys and multisig scripts are nicely unified as a "destination" after all. Why shall BIP 323 break that up again?
legendary
Activity: 1072
Merit: 1174
May 10, 2013, 09:37:29 AM
I imagined constructing multisig addresses of a set of (potentially completely independent) BIP32 chains, using equal indices in each, in lockstep.

In my opinion, BIP32 is mostly about generating sequences of keys, which can either be used directly as pay-to-pubkeyhash addresses, or combined using multisig into a P2SH address. Isn't that both more simple than trying to put BIP32 on top of multisig, and no reason for having the chaincodes be independent?
member
Activity: 104
Merit: 10
May 10, 2013, 08:56:22 AM
About type-2.

Here is a strong argument that re-using chaincodes across different pubkeys makes sense. The argument is multisigs. We can have a multisig address as "parent", which contains several pubkeys, and still a unique chaincode for it, ie. one chaincode for all the pubkeys that appear in the multisig. If I understand Pieter correctly, his concern was to keep the wallet organized around addresses, which serve as the key to a table in which we store the values "pubkey", "privkey", "chaincode" associated to the address. "Extended" multisig addresses can be totally consistent with that: several pubkeys are stored under a multisig address, still only one chaincode. To get a derived multisig address, CKD is applied to each pubkey, each time with the same chaincode.

If you consider hierarchies of multisig addresses this turns into an argument why c_i should not depend on Kpar. Because if the parent is a multisig address, which of the pubkeys should c_i depend on? I say let c_i not depend on any of them. Then you can split your pubkeys across several machines and still derive arbitrary many levels on each machine, even if not all pubkeys of the multisig address are present on the machine. It all seems to fit very natural with how addresses are currently stored and handled.

Summarizing this and my previous post, the suggestion for type-2 (additive version) is:
Code:
K_i := HMAC( HMAC(cpar,i||0), Kpar ) * G + Kpar
c_i := HMAC(cpar,i||1)
Pages:
Jump to: