Beispiel #1
0
    def test_blind_unnblind_sign(self):
        if not secp256k1_has_zkp:
            warn_zkp_unavailable()
            return

        with open(
                os.path.dirname(__file__) + '/data/elements_txs_blinding.json',
                'r') as fd:
            for bundle in json.load(fd):
                blinded_tx_raw = x(bundle['blinded']['hex'])
                blinded_tx = CTransaction.deserialize(blinded_tx_raw)
                self.assertEqual(blinded_tx.serialize(), blinded_tx_raw)
                self.check_serialize_deserialize(blinded_tx, blinded_tx_raw,
                                                 bundle['blinded'])
                unblinded_tx_raw = x(bundle['unblinded']['hex'])
                unblinded_tx = CTransaction.deserialize(unblinded_tx_raw)

                self.assertEqual(unblinded_tx.serialize(), unblinded_tx_raw)
                self.check_serialize_deserialize(unblinded_tx,
                                                 unblinded_tx_raw,
                                                 bundle['unblinded'])
                signed_tx_raw = x(bundle['signed_hex'])
                signed_tx = CTransaction.deserialize(signed_tx_raw)
                self.assertEqual(signed_tx.serialize(), signed_tx_raw)
                blinding_derivation_key = CKey(
                    lx(bundle['blinding_derivation_key']))

                # ensure that str and repr works
                for f in (str, repr):
                    f(unblinded_tx)
                    f(blinded_tx)
                    f(signed_tx)

                if len(blinded_tx.vout) != len(unblinded_tx.vout):
                    assert len(blinded_tx.vout) == len(unblinded_tx.vout) + 1
                    assert blinded_tx.vout[-1].scriptPubKey == b'\x6a',\
                        "expected last output of blinded tx to be OP_RETURN"
                    scriptPubKey = CScript([OP_RETURN])
                    unblinded_tx = unblinded_tx.to_mutable()
                    unblinded_tx.vout.append(
                        CMutableTxOut(
                            nValue=CConfidentialValue(0),
                            nAsset=CConfidentialAsset(
                                unblinded_tx.vout[-1].nAsset.to_asset()),
                            nNonce=CConfidentialNonce(
                                scriptPubKey.derive_blinding_key(
                                    blinding_derivation_key).pub),
                            scriptPubKey=scriptPubKey))
                    unblinded_tx = unblinded_tx.to_immutable()
                    unblinded_tx_raw = unblinded_tx.serialize()

                self.check_blind(unblinded_tx, unblinded_tx_raw, blinded_tx,
                                 blinded_tx_raw, bundle,
                                 blinding_derivation_key)

                self.check_unblind(unblinded_tx, unblinded_tx_raw, blinded_tx,
                                   blinded_tx_raw, bundle,
                                   blinding_derivation_key)

                self.check_sign(blinded_tx, signed_tx, bundle)
Beispiel #2
0
    def check_blind(self,
                    unblinded_tx,
                    unblinded_tx_raw,
                    blinded_tx,
                    blinded_tx_raw,
                    bundle,
                    blinding_derivation_key,
                    asset_commitments=()):
        input_descriptors = []
        for utxo in bundle['vin_utxo']:
            amount = -1 if utxo['amount'] == -1 else coins_to_satoshi(
                utxo['amount'])
            input_descriptors.append(
                BlindingInputDescriptor(
                    amount=amount,
                    asset=CAsset(lx(utxo['asset'])),
                    blinding_factor=Uint256(lx(utxo['blinder'])),
                    asset_blinding_factor=Uint256(lx(utxo['assetblinder']))))

        num_to_blind = 0
        output_pubkeys = []
        for vout in unblinded_tx.vout:
            if not vout.nNonce.is_null() and vout.nValue.is_explicit():
                output_pubkeys.append(CPubKey(vout.nNonce.commitment))
                num_to_blind += 1
            else:
                output_pubkeys.append(CPubKey())

        tx_to_blind = unblinded_tx.to_mutable()

        blind_issuance_asset_keys = []
        blind_issuance_token_keys = []
        for vin in blinded_tx.vin:
            issuance = vin.assetIssuance
            if not issuance.is_null():
                issuance_blinding_script = CScript(
                    [OP_RETURN, vin.prevout.hash, vin.prevout.n])
                blind_issuance_key = issuance_blinding_script.derive_blinding_key(
                    blinding_derivation_key)
                if issuance.nAmount.is_commitment():
                    blind_issuance_asset_keys.append(blind_issuance_key)
                    num_to_blind += 1
                else:
                    blind_issuance_asset_keys.append(None)
                if issuance.nInflationKeys.is_commitment():
                    blind_issuance_token_keys.append(blind_issuance_key)
                    num_to_blind += 1
                else:
                    blind_issuance_token_keys.append(None)
            else:
                blind_issuance_asset_keys.append(None)
                blind_issuance_token_keys.append(None)

        # Deterministic random was used when generating test transactions,
        # to have reproducible results. We need to set the random seed
        # to the same value that was used when test data was generated.
        # (see note below on that supplying _rand_func parameter to blind()
        #  is intended only for testing code, not for production)
        random.seed(bundle['rand_seed'])

        def rand_func(n):
            return bytes([random.randint(0, 255) for _ in range(n)])

        # Auxiliary generators will be be non-empty only for the case
        # when we are blinding different transaction templates that is
        # then combined into one common transaction, that is done in
        # test_split_blinding_multi_sign().
        # In this case, you need to supply the asset commitments for
        # all of the inputs of the final transaction, even if currently
        # blinded transaction template does not contain these inputs.
        blind_result = tx_to_blind.blind(
            input_descriptors=input_descriptors,
            output_pubkeys=output_pubkeys,
            blind_issuance_asset_keys=blind_issuance_asset_keys,
            blind_issuance_token_keys=blind_issuance_token_keys,
            auxiliary_generators=asset_commitments,

            # IMPORTANT NOTE:
            # Specifying custom _rand_func is only required for testing.
            # Here we use it to supply deterministically generated
            # pseudo-random bytes, so that blinding results will match the test
            # data that was generated using deterministically generated random
            # bytes, with seed values that are saved in 'rand_seed' fields of
            # test data bunldes.
            #
            # In normal code you do should NOT specify _rand_func:
            # os.urandom will be used by default (os.urandom is suitable for cryptographic use)
            _rand_func=rand_func)

        self.assertFalse(blind_result.error)

        if all(_k is None for _k in blind_issuance_asset_keys):
            random.seed(bundle['rand_seed'])
            tx_to_blind2 = unblinded_tx.to_mutable()
            blind_result2 = tx_to_blind2.blind(
                input_descriptors=input_descriptors,
                output_pubkeys=output_pubkeys,
                blind_issuance_asset_keys=blind_issuance_asset_keys,
                blind_issuance_token_keys=blind_issuance_token_keys,
                auxiliary_generators=asset_commitments,
                _rand_func=rand_func)
            self.assertFalse(blind_result2.error)
            self.assertEqual(blind_result, blind_result2)
            self.assertEqual(tx_to_blind.serialize(), tx_to_blind2.serialize())

        self.assertEqual(blind_result.num_successfully_blinded, num_to_blind)
        self.assertNotEqual(unblinded_tx_raw, tx_to_blind.serialize())
        self.assertEqual(blinded_tx_raw, tx_to_blind.serialize())