opentimestamps / python-opentimestamps

Other
85 stars 39 forks source link

Add OpSignToContract with tag `0x09` #14

Open apoelstra opened 7 years ago

apoelstra commented 7 years ago

Manually constructed a .ots with txid ff1dca15029d1df57a601f180308bcb6b91f2e8e129668452eaf066cd0668fa6 and verified that it parsed correctly, but since it is still unconfirmed I can't chase it all the way down to a Merkle root yet.

petertodd commented 7 years ago

Niiice!

I should test the re-implementability of this by attempting to implement it in Rust or something.

We might want to call it OpSignToContractSha256. Also, I wonder if the term "contract" makes sense here - most readers probably won't get the reference going forward, even if it's often been called that in the past in the more niche Bitcoin use-cases.

Maybe call it something like EccSigCommitment?

petertodd commented 7 years ago

Or actually, Secp256k1SigCommitment?

apoelstra commented 7 years ago

Here is a .ots that uses this going to block 466872

https://download.wpsoftware.net/bitcoin/wizardry/andytoshi.s2c.ots

Sadly I can't get a file for which this will verify as the original data was the text This is andytoshi on 2017-05-16 21:30 UTC but ots verify adds a newline. (So does sha256sum, irritatingly.)

ACK name change to Secp256k1SigCommitment, will update the PR

Is the tag 0x09 ok?

apoelstra commented 7 years ago

Actually how about just Secp256k1Commitment? This doesn't necessarily have to appear in a signature.

apoelstra commented 7 years ago

Update with renames, also changed the copyright year from 2016 to 2017

petertodd commented 7 years ago

Cool, I like Secp256k1Commitment too!

What do you mean by "ots verify adds a newline"? I mean, ots verify shouldn't be modifying file contents at all. You know about the -n option to echo right?

Tag 0x09 is fine for now; I need to do up a tag allocation list... (or maybe make it a note making it clear that we don't have one?)

apoelstra commented 7 years ago

Oh! It was actually vim silently adding a 0x0a to my file even though I made sure there were no newlines. I removed it with a hex editor and everything works.

You can, in fact, verify the timestamp https://download.wpsoftware.net/bitcoin/wizardry/andytoshi.s2c.ots with the file https://download.wpsoftware.net/bitcoin/wizardry/andytoshi.s2c

:)

petertodd commented 7 years ago

Nice! You should add those two files to the repo; just create an examples/ directory like is in the OpenTimestamps client; we can rearrange or whatever else later.

apoelstra commented 7 years ago

Ok, added

RCasatta commented 7 years ago

Hi @apoelstra this is amazing :) I tested the example and it works. However I am a little bit surprised about ff1dca15029d1df57a601f180308bcb6b91f2e8e129668452eaf066cd0668fa6 size (224 bytes) which is greater than an op_return based one baaac9946198ecad5d8a116aead902ac98e892065adbb446aaee9e1f946e1194 (210 bytes) ff1d.. is saving 34 bytes of the op_return but it's using a longer ScriptSig (139 vs 77) resulting in a bigger transaction. Is there room left to optimize the ScriptSig?

hoffmabc commented 7 years ago

You can just set noeol in binary mode in vim to prevent the newline @apoelstra

petertodd commented 7 years ago

@RCasatta The point of Secp256k1Commitment isn't primarily to make timestmamps smaller, but rather cheaper: since they can be done at zero marginal cost people can timestamp stuff while they're performing Bitcoin transactions that they would have otherwise made anyway.

Now, it's true that we could get both by spending bare CHECKSIG outputs like the OpenTimestamps server does, but that's not the main intent here; once this is implemented I'd still like the calendars to continue making occasional OP_RETURN-based timestamps to protect us in the unlikely event of a major ECC break.

RCasatta commented 7 years ago

@petertodd I perfectly understand the point that you can leverage a transaction someone would made otherwise, but as you said this must come at zero marginal cost to them otherwise it's not viable. Since the ScriptSig of ff1d.. is longer than the average transaction this looked to me that this was not the case. But Maybe I am just not understanding andrew's ScriptSig

petertodd commented 7 years ago

@RCasatta You've got it backwards: Andrews transaction is a normal sized scriptSig; the OpenTimestamps server uses shorter-than-average bare CHECKSIG outputs that can be spent with shorter-than-average scriptSigs.

RCasatta commented 7 years ago

@petertodd Perfect, thanks

petertodd commented 7 years ago

@RCasatta Ah, I just noticed that @apoelstra's transaction was using the 65-byte uncompresed pubkey 0460b56a673caf822f0fa1ad0eb7b9681b001a92a5fb1699c9d0040d980a5fbfc87e92753e1633560dae70622b3e4b207fce6a4207397606d43635b97d33091a03

Most transactions these days use compressed pubkeys, which are 32 bytes shorter.

apoelstra commented 7 years ago

Yes, sorry, I generated very many keys a very long time ago and have not gotten through them all.. hence the uncompressed keys. This is totally separate from sign-to-contract.

RCasatta commented 6 years ago

I would like this to regain attention and I am doing a recap from what I can understand.

Relatively weak points on this are:

Mitigations:

Advantages:

In conclusions, I think we should merge this :)

Concept ACK

apoelstra commented 6 years ago

Sign-to-contract does not introduce a discrete log assumption. It depends only on the security of the underlying hash (in this case, SHA256).

petertodd commented 6 years ago

@apoelstra Do you have a ELI5 explanation as to why that's true? Be good to add that in a comment or something.

apoelstra commented 6 years ago

@LeoComandini in Bitcoin we always serialize points as 33 bytes rather than using DER. Everything is much nicer with fixed-length objects.

@petertodd Sure, there is a (almost) bijection between 32-byte numbers x and points xG. Suppose discrete log is broken so anyone can run this map both ways. Then for all intents and purposes, the map x,k -> kG + H(kG, x)G map is x,k -> k + H(k, x). In the random oracle model, it's easy to see that this map can be used in place of H, since if H is uniformly random and independent of its input then the k-offset cannot affect that.

For fixed k you can also directly prove that first/second preimage resistance or collision resistance hold for H, then the same property will hold for x -> k + H(k,x). This is sufficient for pay-to-contract but not for timestamping, unfortunately.

petertodd commented 6 years ago

FYI, looks like @LeoComandini has actually done a thesis that is in part on the subject of EC commitments! https://github.com/LeoComandini/Thesis/blob/master/main.pdf

apoelstra commented 6 years ago

Oh, nice! Chapter 5 of Leo's thesis has a proof of exactly what you want, in the random oracle model.

@petertodd rebased and added a commit which assets that point-reencoding is unique, and uses the message directly instead of hashing the re-encoding.

petertodd commented 6 years ago

While other commitment operations work on arbitrary input - modulo the MAX_MSG_LENGTH restriction - Secp256k1 introduces new failure modes for when the secp256k1 point is invalid in various ways. I'm not sure this is a good thing, as it complicates error handling, something quite apparent if you try to implement this in a language like Rust that requires functions to specify what errors they may return.

An potential alternative would be to change the semantics in the case of an error to instead, say, output sha256(<unique prefix> + msg) (as in, hash the entire input to the opcode, including the point, with a specific unique prefix). The unique prefix should be the same for all types of errors; I'd suggest just picking a 128bit random number.

If we did this:

The only drawback I can think of is consensus across buggy implementations: if an implementation accidentally raises an error when it shouldn't, that just causes the timestamp to be unusable immediately. With my proposed semantics you might further build on that timestamp by, say, adding additional opcodes that would then be impossible to fix later.

However, as I don't think that risk is unique to my proposal, as you could also have a buggy implementation that thinks a point is valid when it actually isn't. IMO the only lesson there is "don't screw up". :)

While I can't think of any other examples off the top of my head of an opcode that would have a similar problem, I can imagine us using this general approach in the future as well.

apoelstra commented 3 years ago

I should update this to be consistent with https://github.com/ElementsProject/secp256k1-zkp/pull/111 when that gets merged.

Or perhaps I should hold off until the Taproot equivalent.

Interesting thought to interpret invalid points as indicating a different kind of commitment. Now I would suggest using a BIP340 tagged hash with ots/invalidpoint as the tag, or something like that. I agree that, assuming you're right that all existing commitment opcodes are infallible, it would be nice if we didn't have to change that.

petertodd commented 3 years ago

Holding off until Taproot is fine by me. As you can see, I'm in no rush. :)

Good point re: BIP340.