--- Log opened Fri Jan 31 00:00:25 2020 00:19 -!- sipa [~pw@gateway/tor-sasl/sipa1024] has quit [Remote host closed the connection] 00:19 -!- sipa_ [~pw@gateway/tor-sasl/sipa1024] has joined #bitmetas 01:11 -!- jonatack [~jon@2a01:e0a:53c:a200:bb54:3be5:c3d0:9ce5] has quit [Ping timeout: 248 seconds] 01:57 -!- jonatack [~jon@213.152.161.133] has joined #bitmetas 03:38 -!- jonatack [~jon@213.152.161.133] has quit [Ping timeout: 268 seconds] 05:10 -!- jonatack [~jon@2a01:e0a:53c:a200:bb54:3be5:c3d0:9ce5] has joined #bitmetas 05:16 -!- jonatack [~jon@2a01:e0a:53c:a200:bb54:3be5:c3d0:9ce5] has quit [Quit: jonatack] 06:04 -!- jeremyrubin [~jr@c-67-180-60-249.hsd1.ca.comcast.net] has quit [Ping timeout: 268 seconds] 07:52 < sipa_> aj, nickler, real_or_random: so the more i think about how practical implementation of taproot wallets would work, the more i believe we're to a large extent going to keep using 33-byte keys 07:52 < aj> sipa_: hmm. if you're generating a bip32 key, then you convert that to bip340 either by KeyGen(bip32secret) or just dropping of the parity byte as in bip32pubkey[1:33] -- that seems easy to deal with? you just do it after all the derivation stuff 07:54 < sipa_> aj: see my commemt on the PR i just posted 07:55 < aj> sipa_: "looks great on paper" one? 07:55 < sipa_> yeah 07:57 < sipa_> my point is that if effectively the conversion to negated-privkey / xonly pubkey is going to happen only exactly before signing, we better make it part of signimg 08:00 < aj> sipa_: i don't really see it? even if everyone only did the conversion at the last second, that'd just mean KeyGen was breaking out an intermediate function rather than inlining it 08:01 < sipa_> aj: if you see it that way, sure, but is that really what people understand "keygen" to mean? conversion from one key format to a preprocessed ons more suitable for signing? 08:02 < aj> (well, it generates the pubkey too) 08:02 < aj> could make the test vectors have columns for "rand", "sk", "pk", "m", "sig" so people could skip the "sk" column if they want? 08:02 < sipa_> having it as part of signing is also easier to test 08:02 < sipa_> aj: it doesn't "generate" a pubkey as people will long have the pubkey already by that point 08:03 < sipa_> (as it comes out of "old" keygen mechanisms) 08:09 < sipa_> i see what you're saying and you're technically right... it just feels like strange mental overhead 08:09 < sipa_> my message here was more about the fact that in most places of infrastructure, public keys will remain 33-byte things 08:09 < sipa_> just not the signature scheme itself 08:09 -!- sipa_ is now known as sipa 08:10 < aj> (that underscore was strange mental overhead) 08:10 < sipa> good, i got rid of it 08:11 < aj> it'll be 32 bytes in scriptpubkeys and control blocks, and 32bytes (plus a different 33rd byte sometimes) in script 08:11 < aj> i think keeping them as 33-byte things in user-facing stuff is a good idea 08:11 < sipa> yeah i was talking about wallets/signing, not consensus 08:12 < sipa> (though arguably, the control block bit + sPK give the 33-byte Q) 08:12 < aj> not arguably, literally now we're going back to even instead of square? 08:13 < aj> well, except for 0xc0 vs 0x02 part i guess 08:16 < sipa> yeah, and it being split, and it being described differently 08:16 < aj> i wonder if it'd be worth having a top level Convert() if that's the most common way we expect things to happen? i mean it's trivial, but... 08:17 < sipa> the pk-in-sk thing complicates things; otherwise the convert function would be trivial 08:17 < aj> "it doesn't "generate" a pubkey as people will long have the pubkey already by that point" seems like another reason to not be recalculating the pubkey during Sign too though 08:17 < sipa> yeah, it is 08:18 < sipa> but maybe more as an optimization inside implementations 08:18 < sipa> as in, a bip32 derivation implementation that outputs both sk and pk would make a lot of sense 08:18 < aj> does it though? it's just "new_sk || old_sk[1:33]" or "new_sk || bytes(old_P)" if you don't want to assume compressd points? 08:18 < sipa> and taproot tweaking 08:19 < sipa> as in: that's not going to be some long-lived sk object 08:21 < aj> well Sign() as-is doesn't work for tweaking or multisignature or anything anyway? 08:22 < sipa> it does for tweaking if you give it a tweaked key 08:22 < aj> and the taproot tweak doesn't get normalised to even so wouldn't work with KeyGen anyway? 08:22 < aj> oh, i see what you mean 08:22 < sipa> musig, obviously not 08:27 < aj> okay, so you calculate a bip32 priv/pub pair a,A A=a*G. you want to use it as a taproot internal key, and combine it with a script s. but A happens to !have_even_y, so you set p=n-a, P=-A, and get B=P+H(P,s)G. But B is also odd, so you set Q=-B and Q is your pubkey 08:28 < aj> so I'm saying that's p,P = KeyGen(a) q,Q = KeyGen(p+H(P,s)) Sign(q,Q,m) I guess? 08:28 < sipa> right 08:29 < aj> or else maybe I'm saying that's p,P = Convert(a,A) q,Q = KeyGen(p+H(P,s)) Sign(q,Q,m) ? 08:30 < sipa> right; but you also need to be able to compute Q without a 08:30 < aj> right 08:31 < aj> so that would be P=ConvertPub(A) Q=ConvertPub(P+H(P,s)*G) Verify(Q,m,sig) ? 08:32 < sipa> right 08:34 < sipa> but in a PSBT you'll want a record of the form "taproot key Q is derived from A, with tweak s, and then [yes] negated" 08:34 < sipa> so you can't lose track of the original A along the way 08:35 < sipa> and Q + its negation bit are what you get from P+H(...)*G, before you ConvertPub it 08:37 < aj> sipa: so that's p,P = Convert(a,A) (you need to know if you're negating a) and sig = Sign( -(p + H(P,s)), Q, m ) and Verify(Q,m,sig) to check the PSBT wasn't lying about the taproot tweak? 08:38 < sipa> if it was lying, the signature would be invalid i think 08:38 < sipa> (though maybe not something we want to rely on) 08:40 < aj> if Sign() is calculating the pubkey in the above case rather than getitng it as input, it'd be helpful for Sign to output it so you could check it matches the sPK... 08:40 < sipa> hmm, not a big fan of after the fact checking 08:42 < sipa> it shouldn't be needed, i think? 08:43 < sipa> ah yes, but only if you trust Q 08:43 < aj> yeah 08:43 < sipa> which you shouldn't 08:44 < sipa> but you can have computed Q ahead of time 08:44 < aj> either check it beforehand, in which case you might as well pass Q in; or check it afterwards, in which case getting Q out is easier than calculating; or just run Verify() which is more costly than calculating Q=q*G but is also more thorough 08:44 < sipa> or recomouted 08:44 < aj> recomouted? 08:44 < aj> recomputed 08:44 < sipa> recomputed 08:47 < sipa> if you're going to need to recompute Q at signing time anyway, then there is no need for a negation bit in the PSBT record 08:49 < aj> if you don't have the negation bit, you need the KeyGen(p+H(P,s)) step (to calculate P+H(P,s)G and negate if necessary) 08:51 -!- jnewbery [~john@4.53.92.114] has quit [Quit: leaving] 08:51 -!- jnewbery [~john@4.53.92.114] has joined #bitmetas 08:51 -!- jnewbery [~john@4.53.92.114] has quit [Client Quit] 08:51 < sipa> right but you need that step anyway to find Q 08:51 < sipa> or verify it 08:51 -!- jnewbery [~john@4.53.92.114] has joined #bitmetas 08:52 < sipa> no? 08:53 < aj> ... i think that's right? 08:56 < sipa> right, my point is that if signing is insecure without verifying Q, then it needs to be effectively recomputed 08:56 < sipa> in which case the negation bit is unnecessary 08:57 < aj> right 08:59 < aj> i think my point is that if you're verifying Q then you're effectively running the tweaked point through KeyGen even though it's crazy shortlived, and you need the intermediate output at the client level to validate the PSBT info? 09:00 < sipa> intermediate output being Q? 09:00 < aj> yeah 09:00 < sipa> yes, i was more thinking about A and P 09:01 < sipa> where you can't lose A's sign bit 09:01 < sipa> so you can't treat it as a bip340 pubkey 09:02 < aj> ugh, i just got a mental image where the BIP32 path is a taproot with short-lived taproot tweaks coming off it 09:03 < sipa> does tweak in english have any wood related meaning? 09:04 < aj> there's teak? 09:06 < aj> maybe bip32 could be the soil the taproot grows in? 09:06 < sipa> ah, i was confusing with twig 09:14 < real_or_random> I can't follow, can you summarize? 09:15 < sipa> real_or_random: my belief is that for a signicant part of the signer logic, we'll effectively still have 33-byte keys 09:15 < real_or_random> are "negation at keygen" and "64-byte secret keys" entirely different issues or is there a relation? 09:15 < sipa> i think they're unrelated 09:16 < sipa> well, maybe they become 65-byte secret keys 09:17 < real_or_random> ok, and what's your suggestion what keygen should output as a public key? 32 bytes or 33? 09:18 < sipa> i think keygen in practice will be BIP32 09:18 < sipa> and it outputs 33 bytes, and in many cases all 33 bytes need to be kept 09:21 < real_or_random> I think we should make a distinction between something that creates the entropy (BIP32) and the function in the BIP that we currently call keygen 09:21 < sipa> right; aj has been calling it comvert 09:21 < sipa> comvert 09:21 < sipa> coNvert 09:22 < sipa> but BIP32 is doing more than creating the entropy; it's also computing the public key already (with sign flag, which is needed) 09:23 < real_or_random> yes, and there's also public derivation 09:23 < sipa> so at best this convert operation is creating a short-lived certified precomputed privkey/pubkey pair, to avoid redoing it in signing 09:24 < real_or_random> "load_keys" 09:24 < real_or_random> or something 09:24 < real_or_random> like this 09:24 < sipa> an alternative (not sure how i feel about it) is that signing returns the pubkey 09:25 < real_or_random> why would this be helpful in the first place? 09:25 < sipa> to avoid redoing the computation 09:26 < sipa> real_or_random: imagine in a single-key taproot PSBG 09:26 < sipa> PSBT 09:27 < sipa> internal key p, P=pG; output key Q=P+H(P,s)G 09:28 < sipa> in the PSBT file i expect we'd have a map that says "(xonly)Q is derived from (33b)P and merkle root s" 09:28 < sipa> and then the signing device can look up P 09:29 < sipa> now it needs to tweak it 09:29 < aj> '(33b)P' would be a derivation path, no? 09:29 < sipa> well there already is another field with derivation path info for pubkeys 09:30 < sipa> i expect.yet another one to identify a particular key as a musig aggregate 09:31 < sipa> anyway, the point: the signer *has* to verify that Q matches the pubkey he intends to sign for (it can't just take Q from the file and give it to the signing function as we established) 09:31 < real_or_random> hm IIUC you're asking for trouble there. because you'd need to sign first, and only then you can check if you signed the right thing 09:32 < aj> i would've thought you'd have (32B)P and 33B-A-plus-deriv-path; i don't see how 33B-P would make sense, you'd only know its sign if you knew the deriv path 09:32 < real_or_random> if Q is wrong, you should not produce a signature in the first place 09:32 < sipa> either that is done by using this load_keys thing that creates a pubkey + "preprocessed privkey", check the pubkey, and then use the preprocesses data to sign 09:32 < sipa> real_or_random: yeah agree, that's why i wasn't sure about it 09:33 < sipa> aj: but BIP32 isn't the only way P can be generated 09:33 < sipa> especially with musig 09:33 < sipa> and records for 33b-based lookups to master/path already exist; i think those should be reused 09:34 < real_or_random> well or maybe not. I mean in the end you sign for the policy "P+H(P,s)G". if that's not Q, is this a problem? 09:34 < sipa> real_or_random: hmm. 09:35 < sipa> well you'd be putting Q in the signature hash 09:35 < sipa> but use the privkey for P+H(P,s)G 09:35 < real_or_random> no but then sign could just fail 09:36 < sipa> real_or_random: isn't this exactly what we've been talking about? 09:36 < real_or_random> I mean, if sign is supposed to take a pk and output a pk, then it can compare them, no? 09:37 < sipa> that the protection of keyprefixing goes away if the signer can be fed an incorrect pubkey 09:37 < real_or_random> right 09:37 < real_or_random> taking a step back, I think one of the issue is that we have many use cases 09:38 < real_or_random> in particular, the BIP currently is written with tweaking in mind but does not really talk about it 09:40 < real_or_random> maybe sign_with_tweak is not a bad idea? it just takes sk_P, P and s. 09:41 < real_or_random> if you anyway need to recompute Q to verify it's the right one, then you can't use a precomputed Q 09:42 < sipa> agree 09:42 < sipa> i was thinking something similar 09:42 < sipa> and it's actually not true that you need to verify Q; you just need to make sure your own signature is consistent 09:43 < real_or_random> I'm not sure what I say makes sense for all cases, I have the feeling that I don't have a good overview over the entire issue 09:43 < sipa> (its privkey and pubkey match) 09:43 < aj> seems kinda silly not to verify it though? 09:45 < real_or_random> right. but then you can have sign_with_tweak(sk_P, P, s, maybe), and if you pass in a Q then sign can fail if it's the wrong one 09:47 < aj> sipa: hmm, what if our secret keys were 32-bytes s and 33-bytes P=s*G ? 09:49 < sipa> aj:that works, but we shouldn't call thrm secret kegs 09:49 < aj> mmm, secret kegs 09:49 < sipa> maybe "preprocessed keys" or so 09:49 < aj> if they're preprocessed i'd want to ensure they were even already 09:50 < aj> or does that mean KeyGen should just be KeyPreprocess 09:50 < sipa> yeah, i think that also works 09:50 < sipa> if it's just for signing, they can be even 09:51 < sipa> it can return 33b_pk, (32b_sk + 32b_pk) too, if you want full comparison 10:08 < sipa> aj: about what you said earlier... you can have a 32B A and a map(33B -> master/path), but then you'd need to do 2 lookups in the map 10:11 < aj> sipa: right, i guess i was more thinking that you need to have a map Q -> P,s somewhere first, so why not just go direct Q -> master/path, s 10:12 < sipa> yeah, the answer to that is (a) we already have a P->master/path map, and there will be other derivation mechanisms too i expect (musig) 10:13 < aj> i was imagining musig might want to use (unhardened) derivation paths as well 10:16 < sipa> yeah exactly, so you'd have records "key X is derived as bip32 master/path" and records "key X is musig of keys A,B,C" 10:16 < sipa> and they can refer to each other 10:16 < sipa> well, bip32 one can't refer to musig 10:20 < sipa> but i expect all those keys to be full 33b ones 11:04 -!- jonatack [~jon@2a01:e0a:53c:a200:bb54:3be5:c3d0:9ce5] has joined #bitmetas 11:25 -!- jeremyrubin [~jr@c-67-180-60-249.hsd1.ca.comcast.net] has joined #bitmetas 12:18 < real_or_random> so you're saying in general you have a chain of derivation operations (using 33b) and then only at the very end, when you put it on the chain/give it to verifiers, you cut down to 32b 12:19 < sipa> right 12:19 * sipa wonders why real_or_random is awake 12:19 < sipa> oh, oops, +9, not -9 12:20 < real_or_random> right ^^^ 12:20 < real_or_random> ok, that makes a lot of sense (and at least I understand the exact point now) 12:22 < sipa> in output deacriptors you'd use 33 byte pubkeys, too 12:22 < sipa> i think 12:24 < real_or_random> perhaps then it's indeed right to think about this is "preprocessed keys" or "finalized keys" 12:35 < sipa> right 22:54 < aj> okay, so thinking about it more, i think what all this means is that when dealing with secret keys and signing, we want (uint256 dlog, and pubkey33B) while when dealing with verifying we just want (pubkey32B). --- Log closed Sat Feb 01 00:00:26 2020