def authorize_validator_signer_and_bls( self, signer: str, proof_of_signing_key_possession: 'Signature', bls_pub_key: str, bls_pop: str) -> str: """ Authorizes an address to sign consensus messages on behalf of the contract's account. Also switch BLS key at the same time Parameters: signer: str The address of the signing key to authorize proof_of_signing_key_possession: Signature object The contract's account address signed by the signer address bls_pub_key: str The BLS public key that the validator is using for consensus, should pass proof of possession. 48 bytes bls_pop: str The BLS public key proof-of-possession, which consists of a signature on the account address. 96 bytes Returns: str Transaction hash """ account = self.__wallet.active_account.address message = self.web3.soliditySha3(['address'], [account]).hex() prefixed_msg = hash_utils.hash_message_with_prefix(self.web3, message) prefixed_msg = encode_defunct(hexstr=prefixed_msg) pub_key = Account.recover_hash_to_pub( prefixed_msg, vrs=proof_of_signing_key_possession.vrs).to_hex() func_call = self._contract.functions.authorizeValidatorSignerWithKeys( signer, proof_of_signing_key_possession.v, self.web3.toBytes(proof_of_signing_key_possession.r), self.web3.toBytes(proof_of_signing_key_possession.s), pub_key, bls_pub_key, bls_pop) return self.__wallet.send_transaction(func_call)
def validate_attestation_code(self, identifier: str, account: str, issuer: str, code: str) -> bool: """ Validates a given code by the issuer on-chain Parameters: identifier: str Attestation identifier (e.g. phone hash) account: str The address of the account which requested attestation issuer: str The address of the issuer of the attestation code: str The code send by the issuer """ accounts_contract = self.create_and_get_contract_by_name('Accounts') attestation_signer = accounts_contract.get_attestation_signer(issuer) message = self.web3.soliditySha3(['bytes32', 'address'], [identifier, account]).hex() message = encode_defunct(hexstr=message) signer_address = Account.recoverHash(message, signature=code) if signer_address != attestation_signer: raise Exception("Signature was not signed by attestation signer") signature_bytes = HexBytes(code) signature_bytes_standard = to_standard_signature_bytes(signature_bytes) signature_obj = Signature(signature_bytes=signature_bytes_standard) v, r, s = signature_obj.vrs result = self._contract.functions.validateAttestationCode( identifier, account, v, r, s).call() return result != self.null_address
def find_matching_issuer(self, identifier: str, account: str, code: str, issuers: list) -> str: """ Given a list of issuers, finds the matching issuer for a given code Parameters: identifier: str Attestation identifier (e.g. phone hash) account: str Address of the account code: str The code received by the validator (signature) issuers: list The list of potential issuers """ accounts_contract = self.create_and_get_contract_by_name('Accounts') message = self.web3.soliditySha3(['bytes32', 'address'], [identifier, account]).hex() message = encode_defunct(hexstr=message) signer_address = Account.recoverHash(message, signature=code) for issuer in issuers: attestation_signer = accounts_contract.get_attestation_signer( issuer) if attestation_signer == signer_address: return issuer return None
def complete(self, identifier: str, account: str, issuer: str, code: str) -> str: """ Completes an attestation with the corresponding code Parameters: identifier: str Attestation identifier (e.g. phone hash) account: str Address of the account issuer: str The issuer of the attestation code: str The code received by the validator (signature) Returns: Transaction hash """ accounts_contract = self.create_and_get_contract_by_name('Accounts') attestation_signer = accounts_contract.get_attestation_signer(issuer) message = self.web3.soliditySha3(['bytes32', 'address'], [identifier, account]).hex() message = encode_defunct(hexstr=message) signer_address = Account.recoverHash(message, signature=code) if signer_address != attestation_signer: raise Exception("Signature was not signed by attestation signer") signature_bytes = HexBytes(code) signature_bytes_standard = to_standard_signature_bytes(signature_bytes) signature_obj = Signature(signature_bytes=signature_bytes_standard) v, r, s = signature_obj.vrs func_call = self._contract.functions.complete(identifier, v, r, s) return self.__wallet.send_transaction(func_call)
def test_pub_key_recovering(self): accounts = self.kit.w3.eth.accounts account = accounts[0] signer = accounts[1] self.kit.w3.eth.defaultAccount = signer self.kit.wallet_change_account = signer message = self.kit.w3.soliditySha3(['address'], [signer]).hex() message = encode_defunct(hexstr=message) signature = self.kit.wallet.active_account.sign_message(message) self.assertEqual( Account.recover_hash_to_pub(message, vrs=signature.vrs).to_hex(), test_data.recovered_pub_key)
def authorize_validator_signer( self, signer: str, proof_of_signing_key_possession: 'Signature') -> str: """ Authorizes an address to sign validation messages on behalf of the account Parameters: signer: str The address of the validator signing key to authorize proof_of_signing_key_possession: Signature object The account address signed by the signer address Returns: str Transaction hash """ validators_contract = self.create_and_get_contract_by_name( 'Validators') account = self.__wallet.active_account.address if validators_contract.is_validator(account): message = self.web3.soliditySha3(['address'], [account]).hex() prefixed_msg = hash_utils.hash_message_with_prefix( self.web3, message) prefixed_msg = encode_defunct(hexstr=prefixed_msg) pub_key = Account.recover_hash_to_pub( prefixed_msg, vrs=proof_of_signing_key_possession.vrs).to_hex() func_call = self._contract.functions.authorizeValidatorSignerWithPublicKey( signer, proof_of_signing_key_possession.v, self.web3.toBytes(proof_of_signing_key_possession.r), self.web3.toBytes(proof_of_signing_key_possession.s), pub_key) return self.__wallet.send_transaction(func_call) else: func_call = self._contract.functions.authorizeValidatorSigner( signer, proof_of_signing_key_possession.v, self.web3.toBytes(proof_of_signing_key_possession.r), self.web3.toBytes(proof_of_signing_key_possession.s)) return self.__wallet.send_transaction(func_call)