I have a transaction script and trying to make it so that it has a canonical low_s signature for validation purposes. Here is the script:
import __future__
import hashlib
import pycoin
from pycoin.ecdsa import *
import string
import array
import binascii
def rev(str):
ret = ""
for i in range(0, len(str), 2):
ret = str[i:i+2] + ret
return ret
def revbyfours(s):
res = ""
for i in range(int(len(s)/8)):
res += rev(s[8*i:8*i+8])
return res
def verify_sig(sig, prefix, xpub, signed_val):
is_even = (prefix % 2 == 0)
pub_pair = public_pair_for_x(generator_secp256k1, xpub, is_even)
print("sig: (" + hex(sig[0]) + ", " + hex(sig[1]) + ")")
print("pub: (" + hex(pub_pair[0]) + ", " + hex(pub_pair[1]) + ")")
print("hex: " + hex(signed_val))
print("is valid: " + str(verify(generator_secp256k1, pub_pair, signed_val, sig)))
def DoubleHash(string):
bin = binascii.unhexlify(string)
hash = hashlib.sha256(hashlib.sha256(bin).digest()).digest()
raw = str(binascii.hexlify(hash))[2:-1]
return rev(raw)
def DER(r, s):
rlen = int(len(r)/2)
if (rlen == 32 and int(r[0:2], 16) > 0x7F):
rlen += 1
slen = int(len(s)/2)
if (slen == 32 and int(s[0:2], 16) > 0x7F):
slen += 1
res = "30"
res += hex(4 + rlen + slen)[2:].zfill(2)
res += "02"
res += hex(rlen)[2:].zfill(2)
res += r
res += "02"
res += hex(slen)[2:].zfill(2)
res += s
return res
addr = 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'
pubkey_x = 0xzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
pubkey_y = 0xzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
rawtx = '0100000001............................................88ac00000000'
# replacing the '00' scriptSig value
unsigned = ""
unsigned += rawtx[:82]
print (unsigned)
unsigned += '19'+'76a914zzzzzzzzzzzzzzzzzzzzzzzzzzzzz88ac' # scriptSig = scriptPubKey input
print (unsigned)
unsigned += rawtx[84:]
print (unsigned)
unsigned += '01000000' # appending sighash_all
print (unsigned)
unsigned = ''.join(unsigned)
print (unsigned)
unsigned = '0100000001....................................................................e88ac0000000001000000'
# hashToSign
s256 = hashlib.sha256(hashlib.sha256(unsigned_forSig.decode('hex')).digest()).digest()
print ("hash: " + s256)
priv = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1
sig = sk.sign_digest(s256, sigencode=ecdsa.util.sigencode_der)
#r = hex(sig[0])[2:]
#s = hex(sig[1])[2:]
print ("r: " + r)
print ("s: " + s)
derSig = DER(r, s) + "01" # 01 is for sighashall
#these are other options to use
#derSig = hex(int(len(derSig)/2))[2:].zfill(2) + derSig
#sigencode=ecdsa.util.sigencode_der
#sk.sign_digest_deterministic(hash, hashfunc=hashlib.sha256, sigencode=sigencode_string_canonize)
print ("der: " + derSig) #prints out the signature with the DER encoding
# note how the pushdata is in front of the uncompressed pubkey
pub = "4104zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz957bedfb6"
# inserting the signature into the 00 the core software uses in place of ScriptSig
# this prints out a signed raw hexadecimal txn
signed = rawtx[:82] + hex(int(len(derSig + pub)/2))[2:].zfill(2) + derSig + pub + rawtx[84:]
print ("signed: " + signed)
unsigned = '0100000001...........................................88ac0000000001000000'
# note how the pushdata is in front of the uncompressed pubkey
pub = "4104zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz7bedfb6"
# inserting the signature into the 00 the core software uses in place of ScriptSig
# this prints out a signed raw hexadecimal txn
signed = rawtx[:82] + hex(int(len(derSig + pub)/2))[2:].zfill(2) + derSig + pub + rawtx[84:]
print ("signed: " + signed)