Developing Signing vs. Shared Secrets : Journal Entry for 2018 06(June) 23

in steemdev •  6 years ago  (edited)

June 23th, 2018

developing

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:

Dash XjzjT4mr4f7T3E8G9jQQzozTgA2J1ehMkV
LTC LLXj1ZPQPaBA1LFtoU1Gkvu5ZrxYzeLGKt
BitcoinCash 1KVqnW7wZwn2cWbrXmSxsrzqYVC5Wj836u

See also


Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!