Bitcoin Forum
July 06, 2025, 12:38:49 PM *
News: Latest Bitcoin Core release: 29.0 [Torrent]
 
  Home Help Search Login Register More  
  Show Posts
Pages: [1]
1  Bitcoin / Development & Technical Discussion / Emulating OP_CHECKSIGFROMSTACK with OP_CHECKMULTISIG on: September 11, 2024, 07:39:05 AM
I wonder, if it is possible to emulate OP_CHECKSIGFROMSTACK, by using a properly constructed OP_CHECKMULTISIG, for example as a 2-of-2 multisig, where two signatures are given, and the whole task is to find a single public key, which will unlock both, at the same time.

A typical OP_CHECKMULTISIG works like that:
Code:
full script: <signatureAlice> <signatureBob> OP_2 <pubkeyAlice> <pubkeyBob> OP_2 OP_CHECKMULTISIG
input script: <signatureAlice> <signatureBob>
output script: OP_2 <pubkeyAlice> <pubkeyBob> OP_2 OP_CHECKMULTISIG
However, what if we can do instead:
Code:
full script: <pubkeyShared> OP_TOALTSTACK <signatureAlice> <signatureBob> OP_2 OP_FROMALTSTACK OP_DUP OP_2 OP_CHECKMULTISIG
input script: <pubkeyShared>
output script: OP_TOALTSTACK <signatureAlice> <signatureBob> OP_2 OP_FROMALTSTACK OP_DUP OP_2 OP_CHECKMULTISIG
And then, we can be sure, that z-value is identical in both signatures, so we can pick (r,s) pairs in a way, where if someone will provide the proper public key, it will be an equivalent of signing a given message.
Code:
s1=(z+r1*d)/k1
s2=(z+r2*d)/k2
s1*k1=z+r1*d
s2*k2=z+r2*d
z=(s1*k1)-(r1*d)
z=(s2*k2)-(r2*d)
d=((s1*k1)-z)/r1
d=((s2*k2)-z)/r2
Of course, that kind of construction will reveal all private keys. However, by putting the proper (r,s) pairs, it may be possible to put publicly known values here, and just use it as a calculator, which will work as a some kind of "multiply and add a given 256-bit number, by those values". Normally, a regular OP_CHECKSIG would be sufficient here, but OP_CHECKMULTISIG has a nice property of enforcing identical z-value in all signatures.

Or: maybe 3-of-3 multisig, or something bigger is needed, to make a proper OP_CHECKSIGFROMSTACK?
2  Bitcoin / Development & Technical Discussion / Running testnet lottery by miners on: September 08, 2024, 09:34:06 AM
I thought for a long time, how to create a decentralized lottery system, which could work efficiently, without producing too many on-chain transactions, and executing complex on-chain scripts, like HMAC-SHA512.

The first thing we should note is that users are already putting their coins into the system, by paying their transaction fees. Which means, that lottery runner should not require any additional payments, because fees alone should be sufficient to collect all of them, and create an additional output in the coinbase transaction, paid to the winner.

In general, if we analyze the chain history, then for each block, we can easily grab all successfully validated signatures. This is our base for selecting the winner. Because you can't use a coin without exposing its pubkey, by checking all signatures, you will already know, that a given key is spendable, and it was successfully used to move some coins in the current block.

Then, we pick a single public key, no matter in which script type, and which context it was used. Different lottery runners can use different criteria for selecting the winner, because different nodes accept different transactions, some accept free transactions, some may put higher limit, like 10 sat/vB as a minimum, and so on. One winner per block is the highest load we could handle. And it probably should be even lower, like "one winner per N blocks", because lottery runner will obviously not have 100% hashrate domination.

After selecting the winner, we simply create 1-of-2 multisig, where one key is owned by the lottery runner, and another one belongs to the winning user. This is needed, because the default behaviour is to collect 100% transaction fees, which means, that the user lost his bet. Also, during the initial stage of the project, many users will probably be unaware, that they won anything, so there is a need to clean up on-chain UTXOs, if nobody will collect them for a long time.

Also, we should remember, that winning users should have the ability to move their coins. Which means, that if someone paid 110 satoshis for some transaction, and it was the only payment in a given block, then we should not split the coinbase into 50 tBTC for the miner, and 110 satoshis for the lottery. Which means, that there should be some minimal amount of fees, which triggers the lottery, for example set into 1000 satoshis. In other cases, users may end up with dust UTXOs, which they could never move, without some help from the miners.

Another important thing is to use a single pubkey, as a winner, instead of trying to reproduce an exact Script, which was used by a given user. This is needed to make sure, that people can easily spot "lottery vs non-lottery blocks", make sure, that the system is provably fair, and also to avoid huge fees, if someone would win by moving a coin out of 1-of-20 multisig.

When it comes to the exact Script types, then using 1-of-2 bare multisig sounds like a good option. However, it has many drawbacks. First, there are proposals, related to making them non-standard. Which means, that even though coinbase transactions are obviously non-standard, and spending them may be standard for a long time, then still, creating new bare multisig outputs will be considered as spamming, so it should not be used.

However, by avoiding bare multisig, it simply means, that lottery winners will be wrapped in some kind of hash. This is another reason for 1-of-2 multisig, because hashing will hide the fact, that someone won, and it will probably be needed to sweep the prize more often than not.

Another option is to use 1-of-2 Taproot output, where one key is in exposed key, and another is in the TapScript. However, many Taproot outputs are used for spamming, when spending by TapScript, so picking that path would probably create more spam, and we should not encourage that.

Which leaves us with the last option: a regular Segwit single-key address. It is the only case, where something is non-legacy (so it won't be made non-standard soon), and it has predictable transaction size (because a single signature is not a choice, like in Taproot, but a requirement). The drawback is, that it pushes us away from Schnorr signatures, and forces us to use DER encoding, but it is better, than being censored by some nodes, mistakenly marking our address as "maybe Ordinal".

All of that leads us to the final state of the lottery, from the perspective of on-chain observers: usually a single P2WPKH address, when the fees are below 1000 satoshis, and sometimes two P2WPKH addresses, one with the base amount of 50 tBTC, and another one with fees, sent to the 1-of-2 multisig of the winner, and the miner.

Then, the last question remains: how to convert 1-of-2 multisig into a single key? Well, by exploring concepts like Silent Payments, we can find answers. Simply, we take the winner's public key, and multiply it by miner's private key. In this way, we create a shared key, which can be computed only by the winner, and the miner. If we would send it directly into this key, we would achieve 2-of-2 multisig, so we are almost there.

The final modification is to apply SHA-256 on that public key, and use it as a private key. Then, we would have 1-of-2 multisig, but without any information, who spent those coins. Which leads us to yet another concept: Reality Keys.

Of course, the concept of Reality Keys mentions publishing two public keys, but here, we have a single key for the winner. So, how to solve it properly? Well, there is one important key, which is not that well-exposed: the R-value inside the signature. It is obligatory to put something here, when spending the coin, which means, that we can put either miner's R-value here, or winner's R-value.

To achieve that, we can consider building a commitment, as described here: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2023-November/022176.html

As "data", we can use "<winnerSig> <winnerKey> OP_CHECKSIG". Then, any of two parties could release a commitment, but only the winner would have the proper key to create a valid commitment. Which means, that because of 1-of-2 multisig, a miner could potentially broadcast a commitment, containing winner's key, but still: only a winner would have the private key to make this commitment in the first place.

And this fact would be enough to count properly, how many rounds were won by miners, and how many were won by regular users. This is needed, because nodes could exchange those kinds of commitments in a P2P way, and use it as an indicator to pick the winner of the next round (for example by not selecting the same winner over and over again).
3  Bitcoin / Development & Technical Discussion / Raw transaction from Value Overflow Incident on: March 11, 2024, 07:23:25 PM
What is the exact form of raw transaction from Value Overflow Incident? I tried to recreate it, but I guess I am doing something wrong.

Link to the topic: https://bitcointalk.org/index.php?topic=822.0

My attempt:
Code:
decoderawtransaction 0100000001395d705a36b122c01c9be97f8c69994c03bb8a0531990411ce7ac78f34e87f23000000008b483045022100db8ccad098467a80bdb9ae16fca82aa4214a66c1ee24b62b696073e7e4f6879302205ad02d53231be18c5d6a77ffdb39476a5b5da4be70f0acc6794b181f4e38027ca841046b5d97aeed2979207f4ca7d9e75cdebf9ebb2a47d0b715370645f6845edfa7adfb0627ad7bda601ad2d129ebf037c5750841e9ba64ab199c4cb8280a95335d96ffffffff02af63f8ffffffff7f1976a91490e8d5ba1c2a301824b18d383dead728b13ea7b788acaf63f8ffffffff7f1976a9142c72c4b5e0cbf9b6435f2cec9df8668c5075121588ac00000000
{
  "txid": "ffbe549076b4b550088b4eee11106b702ca091efd360de0a6397dd7ca3e36bc1",
  "hash": "ffbe549076b4b550088b4eee11106b702ca091efd360de0a6397dd7ca3e36bc1",
  "version": 1,
  "size": 258,
  "vsize": 258,
  "weight": 1032,
  "locktime": 0,
  "vin": [
    {
      "txid": "237fe8348fc77ace11049931058abb034c99698c7fe99b1cc022b1365a705d39",
      "vout": 0,
      "scriptSig": {
        "asm": "3045022100db8ccad098467a80bdb9ae16fca82aa4214a66c1ee24b62b696073e7e4f6879302205ad02d53231be18c5d6a77ffdb39476a5b5da4be70f0acc6794b181f4e38027ca8 046b5d97aeed2979207f4ca7d9e75cdebf9ebb2a47d0b715370645f6845edfa7adfb0627ad7bda601ad2d129ebf037c5750841e9ba64ab199c4cb8280a95335d96",
        "hex": "483045022100db8ccad098467a80bdb9ae16fca82aa4214a66c1ee24b62b696073e7e4f6879302205ad02d53231be18c5d6a77ffdb39476a5b5da4be70f0acc6794b181f4e38027ca841046b5d97aeed2979207f4ca7d9e75cdebf9ebb2a47d0b715370645f6845edfa7adfb0627ad7bda601ad2d129ebf037c5750841e9ba64ab199c4cb8280a95335d96"
      },
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 92233720368.54277039,
      "n": 0,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 90e8d5ba1c2a301824b18d383dead728b13ea7b7 OP_EQUALVERIFY OP_CHECKSIG",
        "desc": "addr(1EDDEGtrZ5877WPsLU5o9TwjJDqaUqhvte)#h50rucd6",
        "hex": "76a91490e8d5ba1c2a301824b18d383dead728b13ea7b788ac",
        "address": "1EDDEGtrZ5877WPsLU5o9TwjJDqaUqhvte",
        "type": "pubkeyhash"
      }
    },
    {
      "value": 92233720368.54277039,
      "n": 1,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 2c72c4b5e0cbf9b6435f2cec9df8668c50751215 OP_EQUALVERIFY OP_CHECKSIG",
        "desc": "addr(1542Dgx5EeurzHP8cT57fK6hBTQq2dgTEu)#squqxq0e",
        "hex": "76a9142c72c4b5e0cbf9b6435f2cec9df8668c5075121588ac",
        "address": "1542Dgx5EeurzHP8cT57fK6hBTQq2dgTEu",
        "type": "pubkeyhash"
      }
    }
  ]
}
It seems that outputs are decoded properly, because the second address even exists on-chain: https://mempool.space/address/1542Dgx5EeurzHP8cT57fK6hBTQq2dgTEu

However, I am curious about scriptSig, because it is very strange. It has this weird "a8" ending, which sounds like invalid sighash. What is taken in that case? SIGHASH_ALL? Also, I don't know, how to make any message, which will hash into 1d5e512a9723cbef373b970eb52f1e9598ad67e7408077a82fdac194b65333c9. And then, what is the z-value, which is used to make this signature? What are the last four bytes, added to the transaction? Is it "01000000"? Or maybe "a8000000"? Or something else?

In case of the coinbase transaction, that was quite easy:
Code:
decoderawtransaction 01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff08040e80001c028f00ffffffff01c024102d01000000434104750f835e45baa59bda8989092a3f4c7e201bbb6dc2265f12ea4e044b849acfe1656ecf6f4e99516cd9b95486bda27e7c8363798b8ec7a2a8c3f880155da54b4fac00000000
{
  "txid": "012cd8f8910355da9dd214627a31acfeb61ac66e13560255bfd87d3e9c50e1ca",
  "hash": "012cd8f8910355da9dd214627a31acfeb61ac66e13560255bfd87d3e9c50e1ca",
  "version": 1,
  "size": 135,
  "vsize": 135,
  "weight": 540,
  "locktime": 0,
  "vin": [
    {
      "coinbase": "040e80001c028f00",
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 50.51000000,
      "n": 0,
      "scriptPubKey": {
        "asm": "04750f835e45baa59bda8989092a3f4c7e201bbb6dc2265f12ea4e044b849acfe1656ecf6f4e99516cd9b95486bda27e7c8363798b8ec7a2a8c3f880155da54b4f OP_CHECKSIG",
        "desc": "pk(04750f835e45baa59bda8989092a3f4c7e201bbb6dc2265f12ea4e044b849acfe1656ecf6f4e99516cd9b95486bda27e7c8363798b8ec7a2a8c3f880155da54b4f)#r9p0z7n3",
        "hex": "4104750f835e45baa59bda8989092a3f4c7e201bbb6dc2265f12ea4e044b849acfe1656ecf6f4e99516cd9b95486bda27e7c8363798b8ec7a2a8c3f880155da54b4fac",
        "type": "pubkey"
      }
    }
  ]
}
Also, merkle tree was quite easy to decode, because it is just a concatenation of both transaction hashes, with reversed bytes:
Code:
cae1509c3e7dd8bf550256136ec61ab6feac317a6214d29dda550391f8d82c01c93353b694c1da2fa8778040e767ad98951e2fb50e973b37efcb23972a515e1d
5eecb6808d6de56a05211483d86fc6c7d17cda46c3388dd0c8139e4114ba8e61
618eba14419e13c8d08d38c346da7cd1c7c66fd8831421056ae56d8d80b6ec5e
And, for completeness, the 80-byte block header:
Code:
01000000846e2b968653ef0a25a92c12e8884d76919907df8e3079e665686000000000005eecb6808d6de56a05211483d86fc6c7d17cda46c3388dd0c8139e4114ba8e61751e684c0e80001ccf2fae01
1ceca770147b6f7ac697ebdd0bbf9a56abb643ad56c72ef2b30a790000000000
0000000000790ab3f22ec756ad43b6ab569abf0bddeb97c67a6f7b1470a7ec1c
I guess I did some mistake in calculating sighashes, but I don't know exactly, where it is.
4  Alternate cryptocurrencies / Altcoin Discussion / Is secp160k1 with SHA-1 good enough for an altcoin? on: January 20, 2024, 08:41:53 AM
I know that SHA-1 is broken. However, we still have hardened SHA-1, used for example in Git, and in many other places. And as far as I know, the 130-bit public key on secp256k1 is still not sweeped from the puzzle. Which means, that by starting with SHA-1 as a Hashcash function, and with secp160k1 implementation of P2PK on compressed keys, it should be good enough for fully functional altcoin, right?

Because I have some questions, and that kind of experiment should answer them:

1. How could Bitcoin look like, if it would be deployed earlier?
2. How to upgrade the chain, if secp256k1 or SHA-256 will be unsafe?
3. What is the real progress on breaking public keys? Are we really at 130-bit key now, or maybe the creator just moved the funds?

Also, I wonder, which curves below secp160k1 can be used, to reach similar properties, as in Bitcoin. Or: how to prove, that a given public key was created out of N-bit private key, without revealing it?

Another thing is using secq256k1, as a mirror to secp256k1, and create an altcoin, which would just collect proofs, that Bitcoin transactions are signed correctly, by using some kind of Zero Knowledge Proof. And I guess the same can be done with secq160k1, right?
5  Bitcoin / Development & Technical Discussion / What do you think about adding unpruneblockchain command? on: January 03, 2020, 11:34:38 PM
Now, people can prune blocks manually by using pruneblockchain command. Is it acceptable to implement unpruneblockchain, which will redownload missing blocks up to selected height? This command would succeed only if all hashes still matches (meaning there was no blockchain reorganization in pruned blocks and all UTXOs are still correct).
Pages: [1]
Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!