Firma ECDSA y el valor "z"

El siguiente enlace contiene detalles sobre cómo revertir la firma ECDSA si se le dan dos valores "R" idénticos.

http://www.nilsschneider.net/2013/01/28/recovering-bitcoin-private-keys.html

He leído esto y hay una parte que no entiendo; cómo obtuvo los valores "z".

¿Copiar y pegar "OP_DUP OP_HASH160 70792fb74a5df745bac07df6fe020f871cbb293b OP_EQUALVERIFY OP_CHECKSIG" (menos las comillas) en una función hash ripemod-160 produce ese resultado?

¿Tuvo que esencialmente copiar y pegar alguna otra cadena? ¿Acaba de ripemod o sha 256d? ¿Tuvo que hacerlo más de una vez?

He leído sobre estas cosas, pero simplemente no puedo descifrar su descripción de programación de cómo hacerlo. Las descripciones que no son de programación no muestran "hey, este 'xyzx' es a lo que me refiero cuando digo 'mensaje para firmar'" o lo que sea. Muchas cosas en esa página y en el

https://blockchain.info/tx/9ec4bc49e828d924af1d1029cacf709431abbde46d59554b62bc270e3b29c4b1

Parece que podrían describirse adecuadamente como el "mensaje a firmar", además del hecho de que no sé qué tipo de hash se está aplicando para comparar mis cálculos con los que se muestran en el primer enlace.

Respuestas (3)

Calcular los valores Z es bastante complicado para el Joe promedio, así que he creado un sitio web para que lo haga por ti.


Los valores Z para el ejemplo anterior se pueden encontrar en esta página.

https://2xoin.com/tx/9ec4bc49e828d924af1d1029cacf709431abbde46d59554b62bc270e3b29c4b1

También he separado los valores R y S para que te resulte más fácil.

Puede encontrar los valores R, S y Z para todas las transacciones de bitcoin en este sitio.

Otros ejemplos,

https://2xoin.com/tx/9312ccafb8aa624afe7fb7b4201a0ccc2a14ca2b8b8a3253093b975a6a85a280

https://2xoin.com/tx/a963c57ba8a384bf708d5cf83c932e9174ebd0f82f3820e25dcc8a3d508aed54

https://2xoin.com/tx/19d66411a5aa716a04b37197c11c93c9446a54694a2d2302093d8b0a93ed5d83

https://2xoin.com/tx/9778355a53f295a4ffd592af170badda4e9ad3153e15a4afd76655dac387abb2

La respuesta devuelve la respuesta JSON estándar que encuentra en el cliente central de bitcoin, más algunos bits adicionales que agregué que muestran los valores R, S y Z para cada entrada de transacción.

por ejemplo, consulte los nodos SizR, SigS y SigZ a continuación.

{
  "rawtx": "01000000028370ef64eb83519fd14f9d74826059b4ce00eae33b5473629486076c5b3bf215000000008c4930460221009bf436ce1f12979ff47b4671f16b06a71e74269005c19178384e9d267e50bbe9022100c7eabd8cf796a78d8a7032f99105cdcb1ae75cd8b518ed4efe14247fb00c9622014104e3896e6cabfa05a332368443877d826efc7ace23019bd5c2bc7497f3711f009e873b1fcc03222f118a6ff696efa9ec9bb3678447aae159491c75468dcc245a6cffffffffb0385cd9a933545628469aa1b7c151b85cc4a087760a300e855af079eacd25c5000000008b48304502210094b12a2dd0f59b3b4b84e6db0eb4ba4460696a4f3abf5cc6e241bbdb08163b45022007eaf632f320b5d9d58f1e8d186ccebabea93bad4a6a282a3c472393fe756bfb014104e3896e6cabfa05a332368443877d826efc7ace23019bd5c2bc7497f3711f009e873b1fcc03222f118a6ff696efa9ec9bb3678447aae159491c75468dcc245a6cffffffff01404b4c00000000001976a91402d8103ac969fe0b92ba04ca8007e729684031b088ac00000000"
}
{
  "txid": "82e5e1689ee396c8416b94c86aed9f4fe793a0fa2fa729df4a8312a287bc2d5e",
  "version": 1,
  "locktime": 0,
  "vin": [
    {
      "txid": "15f23b5b6c0786946273543be3ea00ceb4596082749d4fd19f5183eb64ef7083",
      "vout": 0,
      "scriptSig": {
        "asm": "30460221009bf436ce1f12979ff47b4671f16b06a71e74269005c19178384e9d267e50bbe9022100c7eabd8cf796a78d8a7032f99105cdcb1ae75cd8b518ed4efe14247fb00c9622[ALL] 04e3896e6cabfa05a332368443877d826efc7ace23019bd5c2bc7497f3711f009e873b1fcc03222f118a6ff696efa9ec9bb3678447aae159491c75468dcc245a6c",
        "hex": "4930460221009bf436ce1f12979ff47b4671f16b06a71e74269005c19178384e9d267e50bbe9022100c7eabd8cf796a78d8a7032f99105cdcb1ae75cd8b518ed4efe14247fb00c9622014104e3896e6cabfa05a332368443877d826efc7ace23019bd5c2bc7497f3711f009e873b1fcc03222f118a6ff696efa9ec9bb3678447aae159491c75468dcc245a6c"
      },
      "sequence": 4294967295,
      "n": 0,
      "addr": "1KtjBE8yDxoqNTSyLG2re4qtKK19KpvVLT",
      "valueSat": 2500000,
      "value": 0.025,
      "doubleSpentTxID": null,
      "sigR": "009bf436ce1f12979ff47b4671f16b06a71e74269005c19178384e9d267e50bbe9",
      "sigS": "00c7eabd8cf796a78d8a7032f99105cdcb1ae75cd8b518ed4efe14247fb00c9622",
      "sigZ": "9f4503ab6cae01b9fc124e40de9f3ec3cb7a794129aa3a5c2dfec3809f04c354"
    },
    {
      "txid": "c525cdea79f05a850e300a7687a0c45cb851c1b7a19a4628565433a9d95c38b0",
      "vout": 0,
      "scriptSig": {
        "asm": "304502210094b12a2dd0f59b3b4b84e6db0eb4ba4460696a4f3abf5cc6e241bbdb08163b45022007eaf632f320b5d9d58f1e8d186ccebabea93bad4a6a282a3c472393fe756bfb[ALL] 04e3896e6cabfa05a332368443877d826efc7ace23019bd5c2bc7497f3711f009e873b1fcc03222f118a6ff696efa9ec9bb3678447aae159491c75468dcc245a6c",
        "hex": "48304502210094b12a2dd0f59b3b4b84e6db0eb4ba4460696a4f3abf5cc6e241bbdb08163b45022007eaf632f320b5d9d58f1e8d186ccebabea93bad4a6a282a3c472393fe756bfb014104e3896e6cabfa05a332368443877d826efc7ace23019bd5c2bc7497f3711f009e873b1fcc03222f118a6ff696efa9ec9bb3678447aae159491c75468dcc245a6c"
      },
      "sequence": 4294967295,
      "n": 1,
      "addr": "1KtjBE8yDxoqNTSyLG2re4qtKK19KpvVLT",
      "valueSat": 2500000,
      "value": 0.025,
      "doubleSpentTxID": null,
      "sigR": "0094b12a2dd0f59b3b4b84e6db0eb4ba4460696a4f3abf5cc6e241bbdb08163b45",
      "sigS": "07eaf632f320b5d9d58f1e8d186ccebabea93bad4a6a282a3c472393fe756bfb",
      "sigZ": "94bbf25ba5b93ba78ee017eff80c986ee4e87804bee5770fae5b486f05608d95"
    }
  ],
  "vout": [
    {
      "value": "0.05000000",
      "n": 0,
      "scriptPubKey": {
        "hex": "76a91402d8103ac969fe0b92ba04ca8007e729684031b088ac",
        "asm": "OP_DUP OP_HASH160 02d8103ac969fe0b92ba04ca8007e729684031b0 OP_EQUALVERIFY OP_CHECKSIG",
        "addresses": [
          "1G3BjSLWsWH6tbPYs29fYMYaz9k8EStQM"
        ],
        "type": "pubkeyhash"
      },
      "spentTxId": "9778355a53f295a4ffd592af170badda4e9ad3153e15a4afd76655dac387abb2",
      "spentIndex": 0,
      "spentHeight": 175915
    }
  ],
  "blockhash": "00000000000006467ae1708979d38dcb6d6fcafbab4c6eccf7414da950379243",
  "blockheight": 175915,
  "confirmations": 309447,
  "time": 1334602008,
  "blocktime": 1334602008,
  "valueOut": 0.05,
  "size": 405,
  "valueIn": 0.05,
  "fees": 0
}

Cuando estaba investigando toda la información en este hilo, creé algunas pequeñas ecuaciones de ayuda que usé mucho mientras experimentaba.

K = ((Z + (X * R)) / S) % N

X = (((S * K) - Z) / R) % N

Z = ((S * K) - (X * R)) % N

S = ((Z + (X * R)) / K) % N

R = (((S * K) - Z) / X) % N

En mis ecuaciones anteriores,

X es la clave privada hexadecimal,

K multiplicado por el valor sep256k1 G produce un ECPoint cuyo valor x = R

Entonces, desde R, puede verificar que tiene el valor K correcto, y si tiene el valor K correcto, puede obtener el valor X correcto, que es el hexadecimal de la clave privada de la dirección en la entrada de la transacción.

Y aquí hay un ejemplo de código C#.

utilizando el sistema;
utilizando System.Linq;
usando Org.BouncyCastle.Math;

espacio de nombres SeansECDSAtest
{
    programa de clase
    {
        vacío estático principal (cadena [] argumentos)
        {
            BigInteger R = nuevo BigInteger(StringToByteArray("00d47ce4c025c35ec440bc81d99834a624875161a26bf56ef7fdc0f5d52f843ad1"));
            BigInteger S = new BigInteger(StringToByteArray("0044e1ff2dfd8102cf7a47c21d5c9fd5701610d04953c6836596b4fe9dd2f53e3e"));
            BigInteger Z = nuevo BigInteger(StringToByteArray("00c0e2d0a89a348de88fda08211c70d1d7e52ccef2eb9459911bf977d587784c6e"));
            BigInteger X = new BigInteger(StringToByteArray("00c477f9f65c22cce20657faa5b2d1d8122336f851a508a1ed04e479c34985bf96"));
            BigInteger K = new BigInteger(StringToByteArray("007a1a7e52797fc8caaa435d2a4dace39158504bf204fbe19f14dbb427faee50ae"));
            BigInteger N = nuevo BigInteger(StringToByteArray("00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"));

            //probando R = (((S * K) - Z) / X) % N
            var verificarR = S.Multiply(K).Restar(Z).Multiply(X.ModInverse(N)).Mod(N);
            Console.WriteLine("R = " + string.Concat(verifyR.ToByteArrayUnsigned().Select(b => b.ToString("X2"))));

            //probando S = ((Z + (X * R)) / K) % N
            var verificarS = Z.Add(X.Multiply(R)).Multiply(K.ModInverse(N)).Mod(N);
            Console.WriteLine("S = " + string.Concat(verifyS.ToByteArrayUnsigned().Select(b => b.ToString("X2"))));

            //probando Z = ((S * K) - (X * R)) % N
            var verificarZ = S.Multiplicar(K).Restar(X.Multiplicar(R)).Mod(N);
            Console.WriteLine("Z = " + string.Concat(verifyZ.ToByteArrayUnsigned().Select(b => b.ToString("X2"))));

            //probando X = (((S * K) - Z) / R) % N
            var verificarX = S.Multiply(K).Restar(Z).Multiply(R.ModInverse(N)).Mod(N);
            Console.WriteLine("X = " + string.Concat(verifyX.ToByteArrayUnsigned().Select(b => b.ToString("X2"))));

            //probando K = ((Z + (X * R)) / S) % N
            var verificarK = Z.Add(X.Multiply(R)).Multiply(S.ModInverse(N)).Mod(N);
            Console.WriteLine("K = " + string.Concat(verifyK.ToByteArrayUnsigned().Select(b => b.ToString("X2"))));

            Consola.ReadLine();
        }

        byte estático público [] StringToByteArray (cadena hexadecimal)
        {
            return Enumerable.Range(0, hex.Length)
                             .Donde(x => x % 2 == 0)
                             .Select(x => Convert.ToByte(hex.Subcadena(x, 2), 16))
                             .ToArray();
        }
    }
}

Y el mismo código en python

def extended_gcd(aa, bb):
    lastremainder, remainder = abs(aa), abs(bb)
    x, lastx, y, lasty = 0, 1, 1, 0
    while remainder:
        lastremainder, (quotient, remainder) = remainder, divmod(lastremainder, remainder)
        x, lastx = lastx - quotient*x, x
        y, lasty = lasty - quotient*y, y
    return lastremainder, lastx * (-1 if aa < 0 else 1), lasty * (-1 if bb < 0 else 1)

def modinv(a, m):
    g, x, y = extended_gcd(a, m)
    if g != 1:
        raise ValueError
    return x % m

R = 0x00d47ce4c025c35ec440bc81d99834a624875161a26bf56ef7fdc0f5d52f843ad1
S = 0x0044e1ff2dfd8102cf7a47c21d5c9fd5701610d04953c6836596b4fe9dd2f53e3e
Z = 0x00c0e2d0a89a348de88fda08211c70d1d7e52ccef2eb9459911bf977d587784c6e
X = 0x00c477f9f65c22cce20657faa5b2d1d8122336f851a508a1ed04e479c34985bf96
K = 0x007a1a7e52797fc8caaa435d2a4dace39158504bf204fbe19f14dbb427faee50ae

N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141

#proving R = (((S * K) - Z) / X) % N
print hex((((S * K) - Z) * modinv(X,N)) % N)

#proving S = ((Z + (X * R)) / K) % N
print hex(((Z + (X * R)) * modinv(K,N)) % N)

#proving Z = ((S * K) - (X * R)) % N
print hex(((S * K) - (X * R)) % N)

#proving X = (((S * K) - Z) / R) % N
print hex((((S * K) - Z) * modinv(R,N)) % N)

#proving K = ((Z + (X * R)) / S) % N
print hex(((Z + (X * R)) * modinv(S,N)) % N)
Gracias, pero lo único que busco es dar sentido a cómo obtener Z, el hash. El resto del algoritmo lo obtengo. Simplemente no entiendo cómo obtener "Z". Eso es todo. El problema es que la mayoría de las respuestas son extremadamente complejas. Sería muy feliz si hubiera algo que tuviera que copiar de la página de transacción de una transacción determinada y pegarlo en algún sitio web, hacer clic en un botón y, BAM, valor Z. De hecho, en este momento, preferiría lo último.
Visite 2coin.org. Muestra los valores Z que puede copiar y pegar. p.ej. 2coin.org/… En la sección de 'entradas', separa los valores de las claves R, S, Z y Public. Si cree que una API podría ser útil para usted, podría armar una con bastante rapidez.
Creé una API para obtener fácilmente los valores Z de las transacciones. He agregado los detalles a mi publicación original arriba.
@SeanBradley echa un vistazo a mi comentario en la respuesta de Willem. ¿Usted me podría ayudar por favor? No puedo obtener el invmod (s1-s2), no es 0xf7d5417b3844fd8f4b3d909979fa7480ce094fb233d759274fd6c3aa6cf86593 en mi caso.
@SeanBradley your result: 0xb440675bdc7cd712ea08fc875df4a8e9f50991650625f25a3a474b6bd6cdb89eL my result: 0x4188f2f2de07b663f48dd0fc2f0d00953fa26c5cb977d374f2a2beac7d459498L Willem's result: 0xf7d5417b3844fd8f4b3d909979fa7480ce094fb233d759274fd6c3aa6cf86593L. No entiendo. Gracias
@lontivero, mira mi demostración en ideone.com/o624rX
@lontivero, cuando pongo código en estos comentarios, nunca funciona, así que creé una pantalla de impresión. Esto me da el resultado correcto. prntscr.com/5g67tf
Fue mi error, Sean. Gracias por tu ayuda.
@SeanBradley Gracias (aunque tarde de mi parte) por toda la ayuda que me brindó. Aunque parece que no puedo hacer que funcionen las API que publicaste. Simplemente se equivocan y no muestran nada. Sé que ha pasado un tiempo, pero ¿podría revisarlos de nuevo, por favor?
todos los enlaces de 2coin.org se redireccionan a biizii.com, parece que se han ido.

nota: lo que Nils Schneider llama 'z', yo lo llamo 'm'.

esta esencia implementa todo esto: https://gist.github.com/nlitsme/dda36eeef541de37d996

el cálculo

La firma de ecdsa se realiza de la siguiente manera:

dado un mensaje 'm', un signo-secreto 'k', una clave privada 'x'

 R = G*k  (elliptic curve scalar multiplication)
 r = xcoordinate(R)
 s = (m + x * r) / k     (mod q)

q = el orden de grupo de secp256k1 = 2^256 - 432420386565659656852420866394968145599

ahora si tenemos 2 firmas con k identicas, podemos escribir esto de la siguiente manera:

 s1 * k = ( m1 + x * r ) (mod q)
 s2 * k = ( m2 + x * r ) (mod q)

restar estas dos ecuaciones, lo que lleva a:

(s1-s2)*k = (m1-m2)      (mod q)

por lo que el secreto de signo 'k' ahora se puede calcular así:

k = (m1-m2)/(s1-s2)      (mod q)

y dado k, la clave privada se puede calcular así:

x = (s1*k-m1) / r        (mod q)

ejemplo practico

Este ejemplo utiliza esta transacción de 2012.

la transacción original

las líneas siguientes representan:

  • el campo de versión

  • el nr de entradas (02)

  • las 2 entradas

  • el nr de salidas (01)

  • La salida

  • el campo de tiempo de bloqueo

    01 00 00 00
    02
     f6 4c 60 3e 2f 9f 4d af 70 c2 f4 25 2b 2d cd b0 7c c0 19 2b 72 38 bc 9c 3d ac ba e5 55 ba f7 01 01 00 00 00  8a 47 30 44 02 20 d4 7c e4 c0 25 c3 5e c4 40 bc 81 d9 98 34 a6 24 87 51 61 a2 6b f5 6e f7 fd c0 f5 d5 2f 84 3a d1 02 20 44 e1 ff 2d fd 81 02 cf 7a 47 c2 1d 5c 9f d5 70 16 10 d0 49 53 c6 83 65 96 b4 fe 9d d2 f5 3e 3e 01 41 04 db d0 c6 15 32 27 9c f7 29 81 c3 58 4f c3 22 16 e0 12 76 99 63 5c 27 89 f5 49 e0 73 0c 05 9b 81 ae 13 30 16 a6 9c 21 e2 3f 18 59 a9 5f 06 d5 2b 7b f1 49 a8 f2 fe 4e 85 35 c8 a8 29 b4 49 c5 ff  ff ff ff ff
     29 f8 41 db 2b a0 ca fa 3a 2a 89 3c d1 d8 c3 e9 62 e8 67 8f c6 1e be 89 f4 15 a4 6b c8 d9 85 4a 01 00 00 00  8a 47 30 44 02 20 d4 7c e4 c0 25 c3 5e c4 40 bc 81 d9 98 34 a6 24 87 51 61 a2 6b f5 6e f7 fd c0 f5 d5 2f 84 3a d1 02 20 9a 5f 1c 75 e4 61 d7 ce b1 cf 3c ab 90 13 eb 2d c8 5b 6d 0d a8 c3 c6 e2 7e 3a 5a 5b 3f aa 5b ab 01 41 04 db d0 c6 15 32 27 9c f7 29 81 c3 58 4f c3 22 16 e0 12 76 99 63 5c 27 89 f5 49 e0 73 0c 05 9b 81 ae 13 30 16 a6 9c 21 e2 3f 18 59 a9 5f 06 d5 2b 7b f1 49 a8 f2 fe 4e 85 35 c8 a8 29 b4 49 c5 ff  ff ff ff ff
    01
     a0 86 01 00 00 00 00 00 19 76 a9 14 70 79 2f b7 4a 5d f7 45 ba c0 7d f6 fe 02 0f 87 1c bb 29 3b 88 ac
    00 00 00 00
    

los guiones de entrada

el script de entrada consta de:

  • la longitud total (8a)

  • la firma

  • la clave publica

    8a
    47 30 44 02 20 d4 7c e4 c0 25 c3 5e c4 40 bc 81 d9 98 34 a6 24 87 51 61 a2 6b f5 6e f7 fd c0 f5 d5 2f 84 3a d1 02 20 44 e1 ff 2d fd 7a 0 2 cf c2 1d 5c 9f d5 70 16 10 d0 49 53 c6 83 65 96 b4 fe 9d d2 f5 3e 3e 01 41 04 db d0 c6 15 32 27 9c f7 29 81 c3 58 4f c3 22 16 e0 12 73 8 9 f9 5 6 49 e0 73 0c 05 9b 81 ae 13 30 16 a6 9c 21 e2 3f 18 59 a9 5f 06 d5 2b 7b f1 49 a8 f2 fe 4e 85 35 c8 a8 29 b4 49 c5 ff

la firma es un valor r+s codificado en asn1 + un indicador de tipo hash (01)

30 44 
    02 20  d4 7c e4 c0 25 c3 5e c4 40 bc 81 d9 98 34 a6 24 87 51 61 a2 6b f5 6e f7 fd c0 f5 d5 2f 84 3a d1
    02 20  44 e1 ff 2d fd 81 02 cf 7a 47 c2 1d 5c 9f d5 70 16 10 d0 49 53 c6 83 65 96 b4 fe 9d d2 f5 3e 3e
01

así que ahora podemos extraer estos valores de la transacción:

pk 04dbd0c61532279cf72981c3584fc32216e0127699635c2789f549e0730c059b81ae133016a69c21e23f1859a95f06d52b7bf149a8f2fe4e8535c8a829b449c5ff
r  d47ce4c025c35ec440bc81d99834a624875161a26bf56ef7fdc0f5d52f843ad1
s1 44e1ff2dfd8102cf7a47c21d5c9fd5701610d04953c6836596b4fe9dd2f53e3e
s2 9a5f1c75e461d7ceb1cf3cab9013eb2dc85b6d0da8c3c6e27e3a5a5b3faa5bab

a continuación, debemos calcular los valores hash del mensaje.

preparar

Elimine los scripts de entrada y agregue el tipo hash

01 00 00 00
02
 f6 4c 60 3e 2f 9f 4d af 70 c2 f4 25 2b 2d cd b0 7c c0 19 2b 72 38 bc 9c 3d ac ba e5 55 ba f7 01 01 00 00 00  00  ff ff ff ff
 29 f8 41 db 2b a0 ca fa 3a 2a 89 3c d1 d8 c3 e9 62 e8 67 8f c6 1e be 89 f4 15 a4 6b c8 d9 85 4a 01 00 00 00  00  ff ff ff ff
01
 a0 86 01 00 00 00 00 00 19 76 a9 14 70 79 2f b7 4a 5d f7 45 ba c0 7d f6 fe 02 0f 87 1c bb 29 3b 88 ac
00 00 00 00
01 00 00 00   <<< hashtype

calculando m1

reemplace la primera entrada con el script de salida correspondiente

01 00 00 00
02
 f6 4c 60 3e 2f 9f 4d af 70 c2 f4 25 2b 2d cd b0 7c c0 19 2b 72 38 bc 9c 3d ac ba e5 55 ba f7 01 01 00 00 00  19 76 a9 14 70 79 2f b7 4a 5d f7 45 ba c0 7d f6 fe 02 0f 87 1c bb 29 3b 88 ac  ff ff ff ff
 29 f8 41 db 2b a0 ca fa 3a 2a 89 3c d1 d8 c3 e9 62 e8 67 8f c6 1e be 89 f4 15 a4 6b c8 d9 85 4a 01 00 00 00  00  ff ff ff ff
01
 a0 86 01 00 00 00 00 00 19 76 a9 14 70 79 2f b7 4a 5d f7 45 ba c0 7d f6 fe 02 0f 87 1c bb 29 3b 88 ac
00 00 00 00
01 00 00 00

luego haz sha256(sha256(transacción modificada))

esto dará como resultado: c0e2d0a89a348de88fda08211c70d1d7e52ccef2eb9459911bf977d587784c6e

calculando m2

reemplace la segunda entrada con el script de salida correspondiente

01 00 00 00
02
 f6 4c 60 3e 2f 9f 4d af 70 c2 f4 25 2b 2d cd b0 7c c0 19 2b 72 38 bc 9c 3d ac ba e5 55 ba f7 01 01 00 00 00  00  ff ff ff ff
 29 f8 41 db 2b a0 ca fa 3a 2a 89 3c d1 d8 c3 e9 62 e8 67 8f c6 1e be 89 f4 15 a4 6b c8 d9 85 4a 01 00 00 00  19 76 a9 14 70 79 2f b7 4a 5d f7 45 ba c0 7d f6 fe 02 0f 87 1c bb 29 3b 88 ac  ff ff ff ff
01
 a0 86 01 00 00 00 00 00 19 76 a9 14 70 79 2f b7 4a 5d f7 45 ba c0 7d f6 fe 02 0f 87 1c bb 29 3b 88 ac
00 00 00 00
01 00 00 00

luego haz sha256(sha256(transacción modificada))

esto dará como resultado: 17b0f41c8c337ac1e18c98759e83a8cccbc368dd9d89e5f03cb633c265fd0ddc

Tenga en cuenta que los scripts de salida canjeados y el script de salida de esta transacción son todos idénticos en este caso. Eso no suele ser así.

entonces nuestros hashes de mensajes son:

m1 c0e2d0a89a348de88fda08211c70d1d7e52ccef2eb9459911bf977d587784c6e
m2 17b0f41c8c337ac1e18c98759e83a8cccbc368dd9d89e5f03cb633c265fd0ddc
s1 44e1ff2dfd8102cf7a47c21d5c9fd5701610d04953c6836596b4fe9dd2f53e3e
s2 9a5f1c75e461d7ceb1cf3cab9013eb2dc85b6d0da8c3c6e27e3a5a5b3faa5bab

m1-m2 = 0xA931DC8C0E011326AE4D6FAB7DED290B196966154E0A73A0DF434413217B3E92
s1-s2 = 0xAA82E2B8191F2B00C8788571CC8BEA41086440225A4B5CBED634D023CFD634D023

inversa modular de s1-s2 = 0xf7d5417b3844fd8f4b3d909979fa7480ce094fb233d759274fd6c3aa6cf86593

entonces nuestro valor secreto 'k' es:

-> (m1-m2)/(s1-s2) = 0x7a1a7e52797fc8caaa435d2a4dace39158504bf204fbe19f14dbb427faee50ae

la clave privada se puede calcular:

s1*k-m1 = 0x797035d79964e4b74fbbef4460379c410261cd01de43278bc2a7efaa541dd8e9 - 0xc0e2d0a89a348de88fda08211c70d1d7e52ccef2eb9459911bf977d587784c6e
= 0xB88D652EFF3056CEBFE1E72343C6CA67D7E3DAF5A1F76E366680D6619CDBCDBC

(s1*k-m1)/r = 0xc477f9f65c22cce20657faa5b2d1d8122336f851a508a1ed04e479c34985bf96

Puedes experimentar con estos cálculos aquí .

Explicación del Contenido de la Transacción

Una transacción consiste en un número de entradas y un número de salidas.

Una entrada se refiere a una de las salidas de otra transacción y contiene un script que prueba que esta transacción puede canjear esa salida.

Una salida consta de un valor BTC y un script que se utilizará para validar la prueba presentada en el script de entrada en el momento en que se canjeará esta salida.

Cuando se canjea una salida, los scripts de entrada y salida son concatenados y evaluados por el cliente bitcoin. el resultado debe ser 'VERDADERO'.

El lenguaje de script es un lenguaje muy simple, no completo, basado en pilas.

El script más común se ve así:

---- input script ( aka scriptSig )
PUSH signature
PUSH publickey
---- output script ( aka scriptPubKey )
DUP
HASH160
PUSH pubkeyhash
EQUALVERIFY
CHECKSIG

Tenga en cuenta que 'PUSH' no está explícitamente etiquetado como PUSH en la descripción del script de bitcoin.

En el script de salida, primero se verifica que la dirección hash (que es la dirección de bitcoin en formato binario) corresponde a la clave pública de la entrada. Luego con CHECKSIGél se verifica que la firma especificada es válida para esta transacción.

Todavía estoy tratando de darle sentido a esta respuesta, bastante compleja. ¿Cuál es la definición de una "entrada" para una transacción? ¿Es el número de direcciones desde las que se envía? ¿Y cuál es la definición de una "salida"? ¿Número de direcciones a las que se envía? Tal vez debería preguntar algo similar. ¿Qué información necesito y cómo la usaría para simplemente enviar mi propia transacción a la red? Punto de clave privada multiplicado por sí mismo K veces, clave pública y ... el hash. Creo que mi principal dificultad es "m" o el "mensaje", toda la "salida", la "entrada" y el "guión" me están confundiendo.
Ahora, de las ecuaciones que mostraste, ¿qué elementos ya se muestran en blockexplorer.com/rawtx/… o blockchain.info/tx/… ? Es decir, digamos que tengo K y quiero resolver x (clave privada) de la manera más simple posible, ¿qué variables para sus ecuaciones originales ya se me muestran? (Sé que esto puede parecer que ya se respondió en su publicación, pero estoy confundido en algunas partes porque he escuchado muchas definiciones para muchas de estas cosas). –
la clave pública, el valor 'r' y 's' se pueden obtener directamente del script de entrada ( scriptSig ). el valor 'm' necesita ser calculado. la 'q' y la 'G' son constantes especificadas por la curva secp256k1 utilizada en bitcoin
Estoy intentando esto de nuevo. Copié y pegué el contenido de la ventana de código debajo de "calcular m1: reemplace la primera entrada con el script de salida correspondiente" y lo puse en una calculadora de algoritmo sha 256d, luego tomé ese resultado y también lo corté, según las instrucciones, los resultados no coincidió con los resultados correctos
modulare inversa de s1-s2? ¿El mod no tiene 2 operandos?
Todos los cálculos son módulo q
Estoy bloqueado en el paso invmod. Esto es lo que obtengo: prntscr.com/5fzzys . ¿Qué estoy haciendo mal? No puedo obtener modulare inverso de s1-s2 = 0xf7d5417b3844fd8f4b3d909979fa7480ce094fb233d759274fd6c3aa6cf86593
el valor en su captura de pantalla de s1-s2 ya es incorrecto, tal vez verifique sus entradas. aquí está el código de trabajo: ideone.com/bjSai7
La clase .NET bigint es un poco complicada, ¡pero lo hice con su ayuda! Gracias @WillemHengeveld
@WillemHengeveld, ¿qué sucede si hay más de una salida? ¿Cómo calculo los valores de M? Es decir, ¿qué debo cambiar en la sección Cálculo de m1 ?
¿Más salidas de qué?
En su ejemplo práctico, la transacción tiene 2 entradas y 1 salida, pero el tx puede tener n salidas. ¿Estoy malinterpretando algo?
la firma está en el script de entrada y utiliza el script de salida de su transacción de origen al calcular el hash del mensaje. Por lo tanto, el número de salidas de la transacción no importa, siempre se cifran sin modificar en el mensaje hash para cada entrada.
2xoin.com también se ha ido ahora, lo cual es desafortunado. Pero gracias por la descripción detallada de sus cálculos y no solo por los enlaces.

¡Solo necesitamos encontrar z1 y z2! Estos son los hashes de las salidas a firmar. Busquemos las transacciones de salida y calculémoslas (se calcula mediante OP_CHECKSIG):

La página de la wiki de Bitcoin en OP_CHECKSIG y la imagen allí muestran lo que está firmado: esencialmente, la nueva transacción con los txin eliminados y la salida de la transacción insertada. Es el hash de estos bytes lo que realmente está firmado, que son z1y z2.

Este pseudocódigo podría ayudar a aclarar cómo zse usan las s:

def sign(priv_key, txin_index):
    z = get_data_to_sign(txin_index) # uses algorithm at https://en.bitcoin.it/w/images/en/7/70/Bitcoin_OpCheckSig_InDetail.png
    r = super_secure_random()
    s = ECDSA_sign(priv_key, z, r)
    return r, s

def verify(pub_key, txin_index, r, s):
    z = get_data_to_sign(txin_index)
    ECDSA_verify(pub_key, z, r, s)

def super_secure_random():
    return 4