def sign(self, private_key): """ Sign check Args: private_key (str) """ if not self.passphrase: raise ValueError('Passphrase should be not empty string') # Prepare structure # It contains nonce, chain_id, due_block, coin, value, lock, v, r, s # lock, v, r, s appended later in code structure = [ int(binascii.hexlify(str(self.nonce).encode()), 16), self.chain_id, self.due_block, MinterConvertor.encode_coin_name(self.coin), MinterConvertor.convert_value(value=self.value, to='pip') ] # Create msg hash msg_hash = self.__hash(structure) # SHA256 from passphrase sha = hashlib.sha256() sha.update(self.passphrase.encode()) passphrase = sha.hexdigest() # Create lock from signature self.lock = self.__lockfromsignature( signature=ECDSA.sign(message=msg_hash, private_key=passphrase) ) # Re-create msg hash with adding lock to structure structure.append(self.lock) msg_hash = self.__hash(structure) # Re-create signature, add it to check attrs and to structure signature = ECDSA.sign(message=msg_hash, private_key=private_key) self.signature = { 'v': signature[0], 'r': format(signature[1], 'x'), 's': format(signature[2], 'x') } structure += signature # Get RLP, which will be the check check = binascii.hexlify(rlp.encode(structure)) return MinterPrefix.CHECK + check.decode()
def get_sender_address(cls, tx): """ Get sender address from tx. Recover public key from tx and then get address from public key, if tx has single signature type, or get decoded sender address, if tx has multi signature type. Args: tx (dict): transaction dict Returns: Minter address (string) """ # Remember signature data and remove it from tx signature_data = tx.pop('signature_data') # If there is sender address in signature data (multi signature tx), return it if signature_data.get('from_mx'): return signature_data['from_mx'] # Otherwise (single signature tx), recover public key and get address from public key # Unhexlify (convert to bin (ascii)) all non-numeric dict values tx = MinterHelper.hex2bin_recursive(tx) # Encode tx data to RLP tx['data'] = rlp.encode(list(tx['data'].values())) # Message tx_rlp = rlp.encode(list(tx.values())) _keccak = MinterHelper.keccak_hash(tx_rlp) # Recover public key public_key = MinterPrefix.PUBLIC_KEY + ECDSA.recover(_keccak, tuple(signature_data.values())) return MinterWallet.get_address_from_public_key(public_key)
def proof(cls, address, passphrase): """ Create proof Args: address (str) passphrase (str) Returns: str """ # Get address hash address = MinterPrefix.remove_prefix( string=address, prefix=MinterPrefix.ADDRESS ) address = MinterHelper.hex2bin(address) address_hash = cls.__hash(data=[address]) # Create SHA256 from passphrase sha = hashlib.sha256() sha.update(passphrase.encode()) passphrase = sha.hexdigest() # Get signature signature = ECDSA.sign(message=address_hash, private_key=passphrase) return binascii.hexlify(cls.__lockfromsignature(signature)).decode()
def sign(self, private_key): """ Sign transaction. This method can be called only from instances of inherited classes. Args: private_key (string): private key Return: string """ # Get structure populated with instance data tx = self._structure_from_instance() # Remove sgnature data, it's not needed before getting Keccak tx.pop('signature_data') # Encode tx data to RLP tx['data'] = rlp.encode(list(tx['data'].values())) # Encode all tx to RLP and create Keccak hash tx_rlp = rlp.encode(list(tx.values())) _keccak = MinterHelper.keccak_hash(tx_rlp) # Signature data tx['signature_data'] = rlp.encode(ECDSA.sign(_keccak, private_key)) tx_rlp = rlp.encode(list(tx.values())) self.signed_tx = binascii.hexlify(tx_rlp).decode()
def recover_public_key(cls, tx): """ Recover public key from tx. Args: tx (dict): transaction dict Returns: public_key (string) """ # Remember signature data and remove it from tx signature_data = tx.pop('signature_data') # Unhexlify (convert to bin (ascii)) all non-numeric dict values tx = MinterHelper.hex2bin_recursive(tx) # Encode tx data to RLP tx['data'] = rlp.encode(list(tx['data'].values())) # Message tx_rlp = rlp.encode(list(tx.values())) _keccak = MinterHelper.keccak_hash(tx_rlp) # Recover public key public_key = ECDSA.recover(_keccak, tuple(signature_data.values())) return MinterPrefix.PUBLIC_KEY + public_key
def sign(self, private_key): """ Sign check Args: private_key (str) """ # Prepare structure # It contains nonce, chain_id, due_block, coin, value, gas_coin, # lock, v, r, s. # lock, v, r, s appended later in code structure = [ int(str(self.nonce).encode().hex(), 16), self.chain_id, self.due_block, MinterHelper.encode_coin_name(self.coin), MinterHelper.to_pip(self.value), MinterHelper.encode_coin_name(self.gas_coin) ] # Create msg hash msg_hash = self.__hash(structure) # SHA256 from passphrase sha = hashlib.sha256() sha.update(self.passphrase.encode()) passphrase = sha.hexdigest() # Create lock from signature self.lock = self.__lockfromsignature( signature=ECDSA.sign(message=msg_hash, private_key=passphrase)) # Re-create msg hash with adding lock to structure structure.append(self.lock) msg_hash = self.__hash(structure) # Re-create signature, add it to check attrs and to structure signature = ECDSA.sign(message=msg_hash, private_key=private_key) self.signature = { 'v': signature[0], 'r': format(signature[1], 'x'), 's': format(signature[2], 'x') } structure += signature # Get RLP, which will be the check check = rlp.encode(structure).hex() return MinterHelper.prefix_add(check, PREFIX_CHECK)
def from_raw(cls, rawcheck): """ Create check instance from raw check Args: rawcheck (str) Returns: MinterCheck """ # Remove check prefix and RLP decode it rawcheck = MinterPrefix.remove_prefix( string=rawcheck, prefix=MinterPrefix.CHECK ) rawcheck = binascii.unhexlify(rawcheck) decoded = rlp.decode(rawcheck) # Create MinterCheck instance kwargs = { 'nonce': int(decoded[0].decode()), 'chain_id': MinterHelper.bin2int(decoded[1]), 'due_block': MinterHelper.bin2int(decoded[2]), 'coin': MinterConvertor.decode_coin_name(decoded[3]), 'value': MinterConvertor.convert_value( value=MinterHelper.bin2int(decoded[4]), to='bip' ), 'lock': binascii.hexlify(decoded[5]).decode(), 'signature': { 'v': MinterHelper.bin2int(decoded[6]), 'r': MinterHelper.bin2hex(decoded[7]), 's': MinterHelper.bin2hex(decoded[8]) } } check = MinterCheck(**kwargs) # Recover owner address msg_hash = cls.__hash(data=[ int(binascii.hexlify(str(check.nonce).encode()), 16), check.chain_id, check.due_block, MinterConvertor.encode_coin_name(check.coin), MinterConvertor.convert_value(value=check.value, to='pip'), MinterHelper.hex2bin(check.lock) ]) public_key = ECDSA.recover(msg_hash, list(check.signature.values())) public_key = MinterPrefix.PUBLIC_KEY + public_key check.owner = MinterWallet.get_address_from_public_key(public_key) return check
def from_raw(cls, rawcheck): """ Create check instance from raw check Args: rawcheck (str) Returns: MinterCheck """ # Remove check prefix and RLP decode it rawcheck = MinterHelper.prefix_remove(rawcheck) rawcheck = bytes.fromhex(rawcheck) decoded = rlp.decode(rawcheck) # Create MinterCheck instance kwargs = { 'nonce': int(decoded[0].decode()), 'chain_id': int.from_bytes(decoded[1], 'big'), 'due_block': int.from_bytes(decoded[2], 'big'), 'coin': MinterHelper.decode_coin_name(decoded[3]), 'value': MinterHelper.to_bip(int.from_bytes(decoded[4], 'big')), 'gas_coin': MinterHelper.decode_coin_name(decoded[5]), 'lock': decoded[6].hex(), 'signature': { 'v': int.from_bytes(decoded[7], 'big'), 'r': decoded[8].hex(), 's': decoded[9].hex() } } check = MinterCheck(**kwargs) # Recover owner address msg_hash = cls.__hash(data=[ int(str(check.nonce).encode().hex(), 16), check.chain_id, check.due_block, MinterHelper.encode_coin_name(check.coin), MinterHelper.to_pip(check.value), MinterHelper.encode_coin_name(check.gas_coin), bytes.fromhex(check.lock) ]) public_key = ECDSA.recover(msg_hash, tuple(check.signature.values())) public_key = MinterHelper.prefix_add(public_key, PREFIX_PUBKEY) check.owner = MinterWallet.get_address_from_public_key(public_key) return check
def generate_signature(self, private_key): """ Create signature for transaction Args: private_key (str): private key to sign with Returns: hex_signature (str) """ # Get structure populated with instance data and rlp encoded tx_struct = self.generate_tx_rlp() # Create keccak hash tx_rlp = rlp.encode(list(tx_struct.values())) keccak = MinterHelper.keccak_hash(tx_rlp) # Create signature signature = ECDSA.sign(keccak, private_key) signature = binascii.hexlify(rlp.encode(signature)).decode() return signature
def proof(cls, address, passphrase=''): """ Create proof Args: address (str) passphrase (str) Returns: str """ # Get address hash address = MinterHelper.prefix_remove(address) address = bytes.fromhex(address) address_hash = cls.__hash(data=[address]) # Create SHA256 from passphrase sha = hashlib.sha256() sha.update(passphrase.encode()) passphrase = sha.hexdigest() # Get signature signature = ECDSA.sign(message=address_hash, private_key=passphrase) return cls.__lockfromsignature(signature).hex()