示例#1
0
 def sum(self, x1, x2):
     # each index is 33 bytes for commitments and 32 for hash
     comm1, hash1 = x1[:33], x1[33:65]
     comm2, hash2 = x2[:33], x2[33:65]
     comm1, comm2 = PedersenCommitment(
         commitment=comm1, raw=True), PedersenCommitment(commitment=comm2,
                                                         raw=True)
     #XXX we definetely need sum of pedersen commitments on libsecp256 level.
     pk = PublicKey()
     pk.combine([
         comm1.to_public_key().public_key,
         comm2.to_public_key().public_key
     ])
     sm = pk.to_pedersen_commitment()
     first_part = sm.serialize()
     second_part = _hash(hash1 + hash2)
     return first_part + second_part
示例#2
0
    def non_context_verify(self, block_height):
        #Actually we partially use context via block_height. Consider renaming.
        try:
            if verification_cache[(self.serialize(), block_height)]:
                #We set coinbase during verification, thus if we scip verification
                #we need to set it manually. TODO (verification should be free from initialisation stuff)
                for output in self.outputs:
                    if output.is_coinbase:
                        self.coinbase = output
                    elif output.is_dev_reward:
                        self.dev_reward = output
                return verification_cache[(self.serialize(), block_height)]
        except KeyError:
            pass

        assert is_sorted(
            self.inputs,
            key=lambda _input: _input.authorized_pedersen_commitment.serialize(
            )), "Inputs are not sorted"
        assert is_sorted(
            self.outputs,
            key=lambda _output: _output.authorized_pedersen_commitment.
            serialize()), "Outputs are not sorted"
        assert is_sorted(
            self.additional_excesses,
            key=lambda e: e.index), "Additional excesses are not sorted"

        assert len(self.inputs) == len(self.updated_excesses)
        for _input in self.inputs:
            assert _input.lock_height < block_height, "Timelocked input"
            s_i = _input.serialized_index
            assert s_i in self.updated_excesses, "Updated excesses do not contain update for address %s" % _input.address.to_text(
            )
            assert _input.address.serialized_pubkey == self.updated_excesses[
                s_i].serialized_pubkey

        #Check that there are no duplicated outputs
        #TODO probably authorized????
        assert len(
            set([
                _output.unauthorized_pedersen_commitment.serialize()
                for _output in self.outputs
            ])) == len(self.outputs), "Duplicated output"

        coinbase_num = 0
        dev_reward_num = 0
        output_apcs = []

        for output in self.outputs:
            assert output.verify(), "Nonvalid output"
            _o_index = output.serialized_index
            output_apcs.append(_o_index[:33])
            if output.is_coinbase:
                coinbase_num += 1
                self.coinbase = output
            elif output.is_dev_reward:
                dev_reward_num += 1
                self.dev_reward = output
        assert coinbase_num < 2, "More then one coinbase"
        assert dev_reward_num < 2, "More then one dev reward output"

        for excess in self.additional_excesses:
            assert excess.verify(), "Nonvalid excess"
            #if not excess.message in output_apcs:
            #  return False
            #else:
            #  output_apcs.remove(excess.message)

        left_side, right_side = [], []

        _t = PublicKey()

        # Transaction should contain outputs (while it may not contain inputs)
        assert len(self.outputs), "Empty outputs"

        if len(self.inputs):
            _t.combine([
                _input.authorized_pedersen_commitment.to_public_key().
                public_key for _input in self.inputs
            ])
            inputs_pedersen_commitment_sum = _t.to_pedersen_commitment()
            left_side.append(inputs_pedersen_commitment_sum)

        if len(self.outputs):
            _t.combine([
                _output.authorized_pedersen_commitment.to_public_key().
                public_key for _output in self.outputs
            ])
            outputs_pedersen_commitment_sum = _t.to_pedersen_commitment()
            right_side.append(outputs_pedersen_commitment_sum)

            _t.combine([
                _output.address.pubkey.public_key for _output in self.outputs
            ])
            outputs_excesses_sum = _t.to_pedersen_commitment()
            left_side.append(outputs_excesses_sum)

        if len(self.additional_excesses):
            _t.combine([
                excess.pubkey.public_key for excess in self.additional_excesses
            ])
            additional_excesses_sum = _t.to_pedersen_commitment()
            left_side.append(additional_excesses_sum)

        if coinbase_num or dev_reward_num:
            minted_value = 0
            if coinbase_num:
                minted_value += self.coinbase.value
            if dev_reward_num:
                minted_value += self.dev_reward.value
            minted_pc = PedersenCommitment(value_generator=default_generator)
            minted_pc.create(minted_value, b'\x00' * 32)
            left_side.append(minted_pc)

        relay_fee = 0
        for _output in self.outputs:
            if not _output.version == 0:
                if _output.generator == default_generator_ser:
                    relay_fee += _output.relay_fee

        new_outputs_fee = self.calc_new_outputs_fee()
        fee = relay_fee + new_outputs_fee
        negative_fee = False
        if fee < 0:
            # It's okay, transaction has consumed so many inputs that it is profitable by itself
            # however we need to handle it manually: libsecp256k1 cannot handle negative value
            negative_fee = True
            fee = -fee

        if not fee == 0:
            fee_pc = PedersenCommitment(value_generator=default_generator
                                        )  #TODO think about fees for assets
            fee_pc.create(fee, b'\x00' * 32)
            if negative_fee:
                left_side.append(fee_pc)
            else:
                right_side.append(fee_pc)

        mixer_pc = (Point(default_blinding_generator) *
                    self.mixer_offset).to_pedersen_commitment(
                    )  #TODO we should optimise here and generate fee_mixer pc
        right_side.append(mixer_pc)

        checker = PedersenCommitment()
        # For transaction which contains coinbase only, both sides will be empty
        if len(left_side) or len(right_side):
            sum_to_zero = checker.verify_sum(left_side, right_side)
            assert sum_to_zero, "Non-zero Pedersen commitments summ"

        if self.coinbase:
            info = self.coinbase.info()
            assert info['exp'] == -1, "Non-transparent coinbase"
            assert self.coinbase.lock_height >= block_height + coinbase_maturity,\
                   "Wrong coinbase maturity timelock: %d should be %d"%(\
                    self.coinbase.lock_height, block_height + coinbase_maturity)
        if self.dev_reward:
            assert self.dev_reward.lock_height >= block_height + dev_reward_maturity, \
                   "Wrong dev reward maturity: %d should be %d"%(\
                    self.dev_reward.lock_height, block_height + dev_reward_maturity)

        tx_skel = TransactionSkeleton(tx=self)
        assert len(tx_skel.serialize(
            rich_format=False)) < 50000, "Too big tx_skeleton"
        verification_cache[(self.serialize(), block_height)] = True
        return True
示例#3
0
    def non_context_verify(self, block_height):
        #Actually we partially use context via block_height. Consider renaming.

        assert is_sorted(
            self.inputs,
            key=lambda _input: _input.authorized_pedersen_commitment.serialize(
            )), "Inputs are not sorted"
        assert is_sorted(
            self.outputs,
            key=lambda _output: _output.authorized_pedersen_commitment.
            serialize()), "Outputs are not sorted"

        for _input in self.inputs:
            assert _input.lock_height < block_height, "Timelocked input"

        #Check that there are no duplicated outputs
        #TODO probably authorized????
        assert len(
            set([
                _output.unauthorized_pedersen_commitment.serialize()
                for _output in self.outputs
            ])) == len(self.outputs), "Duplicated output"

        coinbase_num = 0

        output_apcs = []

        for output in self.outputs:
            assert output.verify(), "Nonvalid output"
            _o_index = output.serialized_index
            output_apcs.append(_o_index[:33])
            if output.version == 0:
                coinbase_num += 1
                self.coinbase = output
        assert coinbase_num < 2, "More then one coinbase"

        for excess in self.additional_excesses:
            assert excess.verify(), "Nonvalid excess"
            if not excess.message in output_apcs:
                return False
            else:
                output_apcs.remove(excess.message)

        left_side, right_side = [], []

        _t = PublicKey()

        # Transaction should contain either outputs (while it may not contain inputs)
        # or combined excesses (for transactions which only delete excesses)
        assert len(self.outputs) or len(
            self.combined_excesses), "Empty outputs"

        if len(self.inputs):
            _t.combine([
                _input.authorized_pedersen_commitment.to_public_key().
                public_key for _input in self.inputs
            ])
            inputs_pedersen_commitment_sum = _t.to_pedersen_commitment()
            left_side.append(inputs_pedersen_commitment_sum)

        if len(self.outputs):
            _t.combine([
                _output.authorized_pedersen_commitment.to_public_key().
                public_key for _output in self.outputs
            ])
            outputs_pedersen_commitment_sum = _t.to_pedersen_commitment()
            right_side.append(outputs_pedersen_commitment_sum)

            _t.combine([
                _output.address.pubkey.public_key for _output in self.outputs
            ])
            outputs_excesses_sum = _t.to_pedersen_commitment()
            left_side.append(outputs_excesses_sum)

        if len(self.additional_excesses):
            _t.combine([
                excess.pubkey.public_key for excess in self.additional_excesses
            ])
            additional_excesses_sum = _t.to_pedersen_commitment()
            left_side.append(additional_excesses_sum)

        if coinbase_num:
            minted_pc = PedersenCommitment(blinded_generator=default_generator)
            minted_pc.create(self.coinbase.value, b'\x00' * 32)
            left_side.append(minted_pc)

        relay_fee = 0
        for _output in self.outputs:
            if not _output.version == 0:
                if _output.generator == default_generator_ser:
                    relay_fee += _output.relay_fee

        new_outputs_fee = self.calc_new_outputs_fee()
        fee = relay_fee + new_outputs_fee

        negative_fee = False
        if fee < 0:
            # It's okay, transaction has consumed so many inputs that it is profitable by itself
            # however we need to handle it manually: libsecp256k1 cannot handle negative value
            negative_fee = True
            fee = -fee

        if not fee == 0:
            fee_pc = PedersenCommitment(blinded_generator=default_generator
                                        )  #TODO think about fees for assets
            fee_pc.create(fee, b'\x00' * 32)
            if negative_fee:
                left_side.append(fee_pc)
            else:
                right_side.append(fee_pc)

        checker = PedersenCommitment()
        # For transaction which contains coinbase only, both sides will be empty
        if len(left_side) or len(right_side):
            sum_to_zero = checker.verify_sum(left_side, right_side)
            assert sum_to_zero, "Non-zero Pedersen commitments summ"

        if not GLOBAL_TEST['skip combined excesses']:
            raise NotImplemented
        if self.coinbase:
            info = self.coinbase.info()
            assert info['exp'] == -1, "Non-transparent coinbase"
            # TODO Ugly ->`self.txos_storage.storage_space.blockchain.current_height`
            assert self.coinbase.lock_height >= block_height + coinbase_maturity,\
                   "Wrong coinbase maturity timelock: %d should be %d"%(\
                    self.coinbase.lock_height, block_height + coinbase_maturity)

        tx_skel = TransactionSkeleton(tx=self)
        assert len(tx_skel.serialize(
            rich_format=False)) < 50000, "Too big tx_skeleton"
        return True