Estoy escribiendo transacciones manualmente y me he topado con una situación bastante extraña.
Solo se acepta una de algunas de las transacciones que transmito a bitcoind; de lo contrario, obtengo una REJECT_NONSTANDARD
(firma DER no canónica).
Así que me ensucie las manos y rastreé el rechazo que se originaba en esta línea: https://github.com/bitcoin/bitcoin/blob/9c5f0d542d1db507b3b9c87bd9de6d0d758d51c1/src/script/interpreter.cpp#L163
Leí sobre la codificación DER y verifiqué cómo IsValidSignatureEncoding
se aplica, pero no sé por qué OpenSSL genera valores no compatibles con DER (r, s).
¿Cómo debo superar esto? Estoy pensando en algo similar a (pseudocódigo):
Pair (r, s);
do
{
(r, s) = sign(hash, pvtkey);
} while (r[0] >= 128 || s[0] >= 128); // where r[0], s[0] should be the very first byte of each value
¿Pero no es eso un poco redundante? ¿Puedo darle a OpenSSL cualquier indicador para producir un par DER (R, S) válido en primer lugar?
Una posible razón es que Bitcoin Core espera un valor S bajo. Intente cambiar s con Ns si s > N/2 (N es el orden de la curva).
Fuente aquí
SCRIPT_ERR_SIG_HIGH_S
) después de anteponer mi valor S defectuoso con un byte 0x00 (leí en otro hilo que debería hacerse si el primer byte de la S inicial es > = 128). Así que sí, lo más probable es que lo que tengo que hacer ahora sea lo que sugeriste.El siguiente código de Python puede crear una firma codificada DER válida dada r
y s
como objetos de byte:
def ser_sig_der(r, s):
sig = b"\x30"
# Make r and s as short as possible
ri = 0
for b in r:
if b == "\x00":
ri += 1
else:
break
r = r[ri:]
si = 0
for b in s:
if b == "\x00":
si += 1
else:
break;
s = s[si:]
# Make positive of neg
first = r[0]
if first & (1 << 7) != 0:
r = b"\x00" + r
first = s[0]
if first & (1 << 7) != 0:
s = b"\x00" + s
# Write total length
total_len = len(r) + len(s) + 4
sig += struct.pack("B", total_len)
# write r
sig += b"\x02"
sig += struct.pack("B", len(r))
sig += r
# write s
sig += b"\x02"
sig += struct.pack("B", len(s))
sig += s
return sig
Es importante tener en cuenta que las firmas en Bitcoin también contienen un byte adicional adjunto a la firma codificada DER que representa el tipo sighash. Deberá agregar ese byte usted mismo.
El tercer byte codifica información sobre la longitud del contenido. Si la longitud del contenido es inferior a 127 bytes, el tercer byte es igual a la longitud del contenido. Si es mayor que 127 y menor que 255, el tercer byte es 0x81. Si es mayor que 255, el tercer byte es 0x82.
Los siguientes bytes indican la longitud del contenido.
Referencia: https://github.com/openssl/openssl/blob/master/crypto/asn1_dsa.c encode_der_length https://www.itu.int/rec/T-REC-X.690-201508-I/en
G.Maxwell