June 23th, 2018
The Need for Signing Versus sharing a password
In both Steemit.com and SteemConnect.com people are asked to share their active key in order to authenticate and do the operations. It is somewhat unavoidable when doing things that require this key. For example, you may use Steemit.com to move funds. SteemConnect can be used to give another App permission to post in your name.
There may be some state that is not part of the blockchain, that needs to be stored on the site hosting. The backend could be in Python, Perl, more Javascript, or even C++. Can we validate a signature in Python? Can we create a signature in Python?
Python Libraries
It turns out there are two libraries for Python. They both demand you use Python3. For myself, if I have to use a package that is not supported by my Linux distribution, I might as well decide which Python3 I want. I decided on Python 3.6 for various reasons.
The first official library is Python Steem and the other is Beem. Beem is more actively maintained than Python Steem and continues to surprise me in how well it works.
Verifying a Signature
Exclusing the setup of the transaction itself, and the subroutine declaration and call, the verification code in Beem can be done in four lines.
from beemgraphenebase.account import PublicKey, PrivateKey
from beembase.signedtransactions import Signed_Transaction
tx = {'ref_block_num': 36029,
'ref_block_prefix': 1164960351,
'expiration': '2016-08-08T12:24:17',
'operations': [['vote',
{'author': 'xeroc',
'permlink': 'piston',
'voter': 'xeroc',
'weight': 10000}]],
'extensions': [],
'signatures': ['200c9c94ba47f8ed7263d1ec7561ee36b74f14cb47cd37059eb7c1a2a19253c8835ca5f814456c0cf01b5ed9db34f79c95f9b55fbb12a4780c1e97aec29ff05416']
}
txs = Signed_Transaction(**tx)
txs.deriveDigest("STEEM")
pubkeys = [PublicKey("STM7a4zu9FdZueupx4tH8yWe12aLTT4CE7rvDH7kEKLiaefd29n5d")]
txs.verify(pubkeys, "STEEM")
In the other Python Steem library the verification works like this (Taken from the gist):
import struct
import time
from calendar import timegm
from binascii import hexlify, unhexlify
import hashlib
import ecdsa
from pistonbase.account import PrivateKey
from pistonbase import transactions
tx2 = transactions.Signed_Transaction(**tx)
tx2.deriveDigest("STEEM")
pubkeys = [PrivateKey(p).pubkey for p in wifs]
tx2.verify(pubkeys, "STEEM")
If there is an error, an exception gets thrown. The transaction has a valid signature if there is no exception thrown. Of course the transaction itself could be invalid or expired but verify() does not check that.
Signing a Transaction
Using Beem, I couldn't simply (in ten lines or less) reproduce the signature found in the example over on github but they do verify! That is to say, the signatures generated may not be the expected right answer but the signatures are distinct right answers.
from beembase import transactions
from beem import Steem
from beemgraphenebase.account import PublicKey, PrivateKey
from beembase.signedtransactions import Signed_Transaction
from copy import copy
import time
from calendar import timegm
# constants
tx_base = {'ref_block_num': 36029,
'ref_block_prefix': 1164960351,
'expiration': '2016-08-08T12:24:17',
'operations': [['vote',
{'author': 'xeroc',
'permlink': 'piston',
'voter': 'xeroc',
'weight': 10000}]],
'extensions': [],
'signatures': []
}
signatures = ['200c9c94ba47f8ed7263d1ec7561ee36b74f14cb47cd37059eb7c1a2a19253c8835ca5f814456c0cf01b5ed9db34f79c95f9b55fbb12a4780c1e97aec29ff05416']
private_key = "5JLw5dgQAx6rhZEgNN5C2ds1V47RweGshynFSWFbaMohsYsBvE8"
steem = Steem()
def verify_signature(signature):
tx = copy(tx_base)
if type(signature) == list:
tx['signatures'] = signature
elif str(signature) == str:
tx['signatures'] = [signature]
else:
raise Exception("Invalid parameter")
txs = transactions.Signed_Transaction(**tx)
txs.deriveDigest("STEEM")
pubkeys = [PublicKey("STM7a4zu9FdZueupx4tH8yWe12aLTT4CE7rvDH7kEKLiaefd29n5d")]
txs.verify(pubkeys, "STEEM")
def create_signature_attempt1():
from beem.transactionbuilder import TransactionBuilder
tx = copy(tx_base)
txb = TransactionBuilder(tx=tx, steem_instance=steem, nobroadcast=True)
txb.appendWif(private_key)
txs = txb.sign(reconstruct_tx=False)
verify_signature(txs.json().get('signatures'))
def create_signature_attempt2():
stx = Signed_Transaction(**copy(tx_base))
# format of private key
stx.deriveDigest("STEEM")
stx.sign([private_key], chain=steem.chain_params)
verify_signature(stx.json().get('signatures'))
create_signature_attempt1()
create_signature_attempt2()
verify_signature(signatures)
Signing is just three lines of Python code:
txb = TransactionBuilder(tx=tx, steem_instance=steem, nobroadcast=True)
txb.appendWif(private_key)
assert txb.json() == tx_base
txs = txb.sign(reconstruct_tx=False)
Previous Journal Entries:
- June 15th Looking for volunteers
- March 16th Developing Steemfiles, History in Javascript
- March 15th Developing Keybox, a signer, and a broadcaster
- March 14th (Working on a new Wallet
- March 13th (importance of source control, showing Public Keys, Politics Utopian)
- March 12th (keyring package for python) listing)
- March 10th (Keybox full working source code listing)
- March 9th
- March 8th
Dash XjzjT4mr4f7T3E8G9jQQzozTgA2J1ehMkV
LTC LLXj1ZPQPaBA1LFtoU1Gkvu5ZrxYzeLGKt
BitcoinCash 1KVqnW7wZwn2cWbrXmSxsrzqYVC5Wj836u
See also