Example #1
0
    def verify(self, signature, message):
        """ Verify signature, raise exception if it is not valid.

        :param message: sequance of bytes, raw format or hexadecimal notation
        :param signature: a signature in base58 encoding
        :raises: ValueError if signature is not valid
        """
        signature = scrub_input(signature)
        message = scrub_input(message)

        if not self.public_point:
            raise ValueError("Cannot verify without a public key")

        if signature[:3] != b'sig':  # not generic
            if self.curve != signature[:2]:  # "sp", "p2" "ed"
                raise ValueError("Signature and public key curves mismatch.")

        signature = base58_decode(signature)

        # Ed25519
        if self.curve == b"ed":
            digest = pysodium.crypto_generichash(message)
            try:
                pysodium.crypto_sign_verify_detached(signature, digest,
                                                     self.public_point)
            except ValueError:
                raise ValueError('Signature is invalid.')
        # Secp256k1
        elif self.curve == b"sp":
            pk = secp256k1.PublicKey(self.public_point, raw=True)
            sig = pk.ecdsa_deserialize_compact(signature)
            if not pk.ecdsa_verify(message, sig, digest=blake2b_32):
                raise ValueError('Signature is invalid.')
        # P256
        elif self.curve == b"p2":
            pk = fastecdsa.encoding.sec1.SEC1Encoder.decode_public_key(
                self.public_point, curve=fastecdsa.curve.P256)
            r, s = bytes_to_int(signature[:32]), bytes_to_int(signature[32:])
            if not fastecdsa.ecdsa.verify(
                    sig=(r, s), msg=message, Q=pk, hashfunc=blake2b_32):
                raise ValueError('Signature is invalid.')
        else:
            assert False
Example #2
0
    def from_encoded_key(cls, key, passphrase=''):
        """
        Creates a key object from a base58 encoded key.
        :param key: a public or secret key in base58 encoding
        :param passphrase: the passphrase used if the key provided is an encrypted private key
        """
        key = scrub_input(key)

        curve = key[:2]  # "sp", "p2" "ed"
        if curve not in [b'sp', b'p2', b'ed']:
            raise ValueError("Invalid prefix for a key encoding.")
        if not len(key) in [54, 55, 88, 98]:
            raise ValueError("Invalid length for a key encoding.")

        encrypted = (key[2:3] == b'e')
        public_or_secret = key[3:5] if encrypted else key[2:4]
        if public_or_secret not in [b'pk', b'sk']:
            raise Exception("Invalid prefix for a key encoding.")

        key = base58_decode(key)
        is_secret = (public_or_secret == b'sk')
        if not is_secret:
            return cls.from_public_point(key, curve)

        if encrypted:
            if not passphrase:
                raise ValueError(
                    "Encrypted key provided without a passphrase.")

            salt, encrypted_sk = key[:8], key[8:]
            encryption_key = hashlib.pbkdf2_hmac(
                hash_name="sha512",
                password=scrub_input(passphrase),
                salt=salt,
                iterations=32768,
                dklen=32)
            key = pysodium.crypto_secretbox_open(c=encrypted_sk,
                                                 nonce=b'\000' * 24,
                                                 k=encryption_key)
            del passphrase

        return cls.from_secret_exponent(key, curve)
Example #3
0
 def test_b58_decode_encode(self, string, prefix):
     data = base58_decode(string)
     result = base58_encode(data, prefix)
     self.assertEqual(string, result)
Example #4
0
 def watermark(self):
     """
     Chain watermark, hex encoded
     """
     data = self.chain_id()
     return hexlify(base58_decode(data.encode())).decode()
Example #5
0
 def signed_bytes(self):
     signature_bytes = hexlify(base58_decode(self.get('signature'))).decode()
     return self.forge() + signature_bytes
Example #6
0
    def test_transaction_low_level(self):
        try:
            head_hash = self.shell.head.hash()

            contract = self.shell.head.context.contracts[self.pkh1]
            counter = int(contract.counter()) + 1

            constants = self.shell.head.context.constants()
            #logger.debug(f"constants = {pformat(constants)}")
            gas_limit = constants['hard_gas_limit_per_operation']
            storage_limit = constants['hard_storage_limit_per_operation']

            trans_oper = tezos.make_transaction_operation(
                self.pkh1,
                self.pkh2,
                17,
                head_hash,
                signature=self.fake_sig,
                counter=counter,
                gas_limit=gas_limit)
            #print(f"oper = {pformat(trans_oper)}")
            resp = self.node.post(
                "/chains/main/blocks/head/helpers/scripts/run_operation",
                json=trans_oper)

            trans_oper = trans_oper['contents'][0]
            resp_oper = resp['contents'][0]
            self.assertEqual(resp_oper['counter'], trans_oper['counter'])
            self.assertEqual(resp_oper['kind'], "transaction")

            result = resp_oper['metadata']['operation_result']
            self.assertEqual(result['status'], 'applied',
                             f'result = {pformat(result)}')

            consumed_gas = int(result['consumed_gas'])
            self.assertGreater(consumed_gas, 1000)

            storage_used = 0  # TODO: how to get this? not appearing in results from scriptless address

            protocols = self.shell.head.protocols()
            protocol = protocols.get("protocol")
            self.assertRegex(protocol, r"^P")

            trans_oper2 = tezos.make_transaction_operation(
                self.pkh1,
                self.pkh2,
                17,
                head_hash,
                counter=counter,
                gas_limit=consumed_gas + 100,
                storage_limit=0)

            resp2 = self.node.post(
                "/chains/main/blocks/head/helpers/forge/operations",
                json=trans_oper2)
            self.assertRegex(resp2, r"^[a-f0-9]+$")
            oper_hex = resp2

            signature = self.key1.sign("03" + oper_hex)
            self.assertRegex(signature, r"^edsig")

            trans_oper3 = tezos.make_transaction_operation(
                self.pkh1,
                self.pkh2,
                17,
                head_hash,
                counter=counter,
                gas_limit=consumed_gas + 100,
                storage_limit=0,
                protocol=protocol,
                signature=signature)
            resp3 = self.node.post(
                "/chains/main/blocks/head/helpers/preapply/operations",
                json=[trans_oper3])

            raw_signature = base58_decode(signature.encode())
            hex_signature = raw_signature.hex()

            signed_oper_hex = oper_hex + hex_signature

            resp4 = self.node.post("/injection/operation?chain=main",
                                   signed_oper_hex)
            logger.debug(f"\nresp4 = {pformat(resp4)}\n")

        except RpcError as exc:
            formatted_error_str = json.dumps(json.loads(exc.res.text),
                                             indent=2)
            logger.error(f"\nRpcError: {formatted_error_str}\n")
Example #7
0
 def get_chain_watermark(self):
     assert isinstance(self, RpcQuery)
     data = self._node.get(f'chains/{self.get_chain_id()}/chain_id')
     return hexlify(base58_decode(data.encode())).decode()