예제 #1
0
    def fill_round_1(self, t_1: PublicKey, t_2: PublicKey):
        if self.t_1 is None:
            self.t_1 = t_1.clone(self.secp)
        else:
            self.t_1.add_assign(self.secp, t_1)

        if self.t_2 is None:
            self.t_2 = t_2.clone(self.secp)
        else:
            self.t_2.add_assign(self.secp, t_2)
예제 #2
0
    def build_transactions(self):
        assert self.role == Role.SELLER and self.stage == Stage.LOCK, "Incorrect stage"

        # Check output range proof
        output = Output(OutputFeatures.DEFAULT_OUTPUT, self.commit,
                        self.range_proof)
        assert output.verify(self.secp), "Invalid bulletproof"

        # Build refund tx
        refund_input = Input(OutputFeatures.DEFAULT_OUTPUT, self.commit)

        public_refund_nonce_sum = PublicKey.from_combination(
            self.secp,
            [self.public_refund_nonce, self.foreign_public_refund_nonce])

        refund_signature = aggsig.add_partials(self.secp, [
            self.partial_refund_signature,
            self.foreign_partial_refund_signature
        ], public_refund_nonce_sum)
        assert aggsig.verify(
            self.secp, refund_signature, self.public_refund_excess,
            self.refund_fee_amount,
            self.refund_lock_height), "Unable to verify refund signature"

        refund_kernel = Kernel(0, self.refund_fee_amount,
                               self.refund_lock_height, None, None)
        self.refund_tx = Transaction([refund_input], [self.refund_output],
                                     [refund_kernel], self.refund_offset)
        refund_kernel.excess = self.refund_tx.sum_commitments(self.secp)
        refund_kernel.excess_signature = refund_signature
        assert self.refund_tx.verify_kernels(
            self.secp), "Unable to verify refund kernel"

        # Build multisig tx
        public_nonce_sum = PublicKey.from_combination(
            self.secp, [self.public_nonce, self.foreign_public_nonce])

        signature = aggsig.add_partials(
            self.secp,
            [self.partial_signature, self.foreign_partial_signature],
            public_nonce_sum)
        assert aggsig.verify(self.secp, signature, self.public_excess, self.fee_amount, self.lock_height), \
            "Unable to verify signature"

        kernel = Kernel(0, self.fee_amount, self.lock_height, None, None)
        self.tx = Transaction(self.inputs, [self.change_output, output],
                              [kernel], self.offset)
        kernel.excess = self.tx.sum_commitments(self.secp)
        kernel.excess_signature = signature
        assert self.tx.verify_kernels(self.secp), "Unable to verify kernel"

        self.swap_nonce = SecretKey.random(self.secp)
        self.public_swap_nonce = self.swap_nonce.to_public_key(self.secp)
예제 #3
0
 def to_public_key(self, secp) -> PublicKey:
     assert isinstance(secp, Secp256k1)
     obj = PublicKey(secp)
     res = lib.secp256k1_pedersen_commitment_to_pubkey(
         secp.ctx, obj.key, self.commitment)
     assert res, "Unable to convert to public key"
     return obj
예제 #4
0
 def bullet_proof_multisig_1(
         self, value: int, blind: SecretKey, commit: Commitment,
         common_nonce: SecretKey, nonce: SecretKey,
         extra_data: bytearray) -> (PublicKey, PublicKey):
     scratch = lib.secp256k1_scratch_space_create(self.ctx, 256 * MAX_WIDTH)
     t_1 = PublicKey(self)
     t_2 = PublicKey(self)
     blind_key = ffi.new("char []", bytes(blind.key))
     res = lib.secp256k1_bulletproof_rangeproof_prove(
         self.ctx, scratch, self.gens, ffi.NULL, ffi.NULL, ffi.NULL,
         t_1.key, t_2.key, [value], ffi.NULL, [blind_key],
         [commit.commitment], 1, self.GENERATOR_H, 64,
         bytes(common_nonce.key), bytes(nonce.key), bytes(extra_data),
         len(extra_data), ffi.NULL)
     lib.secp256k1_scratch_space_destroy(scratch)
     assert res, "Unable to generate multisig bulletproof"
     return t_1, t_2
def test_sig():
    # Test Grin-like signature scheme
    secp = Secp256k1(None, FLAG_ALL)
    nonce_a = SecretKey.random(secp)
    public_nonce_a = nonce_a.to_public_key(secp)
    nonce_b = SecretKey.random(secp)
    public_nonce_b = nonce_b.to_public_key(secp)
    public_nonce_sum = PublicKey.from_combination(
        secp, [public_nonce_a, public_nonce_b])
    excess_a = SecretKey.random(secp)
    public_excess_a = excess_a.to_public_key(secp)
    excess_b = SecretKey.random(secp)
    public_excess_b = excess_b.to_public_key(secp)
    public_excess_sum = PublicKey.from_combination(
        secp, [public_excess_a, public_excess_b])
    fee = randint(1, 999999)
    lock_height = randint(1, 999999)

    # Partial signature for A
    sig_a = aggsig.calculate_partial(secp, excess_a, nonce_a,
                                     public_excess_sum, public_nonce_sum, fee,
                                     lock_height)
    assert aggsig.verify_partial(secp, sig_a, public_excess_a,
                                 public_excess_sum, public_nonce_sum, fee,
                                 lock_height)

    # Partial signature for B
    sig_b = aggsig.calculate_partial(secp, excess_b, nonce_b,
                                     public_excess_sum, public_nonce_sum, fee,
                                     lock_height)
    assert aggsig.verify_partial(secp, sig_b, public_excess_b,
                                 public_excess_sum, public_nonce_sum, fee,
                                 lock_height)

    # Total signature
    sig = aggsig.add_partials(secp, [sig_a, sig_b], public_nonce_sum)
    assert aggsig.verify(secp, sig, public_excess_sum, fee, lock_height)
    rnd_sig = Signature(bytearray(urandom(64)))
    assert not aggsig.verify(secp, rnd_sig, public_excess_sum, fee,
                             lock_height)
    public_rnd = SecretKey.random(secp).to_public_key(secp)
    assert not aggsig.verify(secp, sig, public_rnd, fee, lock_height)
    assert not aggsig.verify(secp, sig, public_excess_sum, 0, lock_height)
    assert not aggsig.verify(secp, sig, public_excess_sum, fee, 0)
예제 #6
0
    def fill_swap_signatures(self):
        buyer = self.role == Role.BUYER
        assert (buyer and self.stage == Stage.LOCK) or (
            not buyer and self.stage == Stage.SWAP), "Incorrect stage"

        # Public (total) swap excess
        pos = [
            self.swap_output.commit,
            self.secp.commit_value(self.swap_fee_amount)
        ]
        neg = [self.commit, self.secp.commit(0, self.swap_offset)]
        self.public_swap_excess = self.secp.commit_sum(pos, neg).to_public_key(
            self.secp)

        # Partial swap excess
        swap_blind_sum = BlindSum()
        swap_blind_sum.sub_child_key(self.partial_child)
        if buyer:
            swap_blind_sum.add_child_key(self.swap_child)
            swap_blind_sum.sub_blinding_factor(self.swap_offset)
        swap_excess = self.wallet.chain.blind_sum(
            swap_blind_sum).to_secret_key(self.secp)

        # Nonce sum
        public_swap_nonce_sum = PublicKey.from_combination(
            self.secp,
            [self.public_swap_nonce, self.foreign_public_swap_nonce])

        if not buyer:
            # Verify that partial signature is valid with swap secret
            pos = [self.swap_output.commit]
            neg = [
                self.foreign_partial_commit,
                self.secp.commit(0, self.swap_offset),
                self.secp.commit_value(self.grin_amount - self.swap_fee_amount)
            ]
            foreign_public_partial_swap_excess = self.secp.commit_sum(
                pos, neg).to_public_key(self.secp)

            assert aggsig.verify_partial_adaptor(
                self.secp, self.foreign_partial_swap_adaptor,
                foreign_public_partial_swap_excess, self.public_lock,
                self.public_swap_excess, public_swap_nonce_sum,
                self.swap_fee_amount,
                self.swap_lock_height), "Partial swap signature not valid"

        # Partial swap signature
        self.partial_swap_signature = aggsig.calculate_partial(
            self.secp, swap_excess, self.swap_nonce, self.public_swap_excess,
            public_swap_nonce_sum, self.swap_fee_amount, self.swap_lock_height)

        if buyer:
            self.partial_swap_adaptor = aggsig.calculate_partial_adaptor(
                self.secp, swap_excess, self.swap_nonce, self.secret_lock,
                self.public_swap_excess, public_swap_nonce_sum,
                self.swap_fee_amount, self.swap_lock_height)
예제 #7
0
def create_common_nonce(secp: Secp256k1, secret_key: SecretKey,
                        public_key: PublicKey,
                        commit: Commitment) -> SecretKey:
    common_key = public_key.mul(secp, secret_key)
    return SecretKey.from_bytearray(
        secp,
        bytearray(
            blake2b(bytes(common_key.to_bytearray(secp)),
                    digest_size=32,
                    key=bytes(commit.to_bytearray(secp))).digest()))
    def finalize_swap(self):
        seller = self.role == Role.SELLER
        assert (seller and self.stage == Stage.DONE) or (
            not seller and self.stage == Stage.SWAP), "Incorrect stage"

        if seller:
            self.secret_lock = self.foreign_partial_swap_adaptor.scalar(
                self.secp).add(
                    self.secp,
                    self.foreign_partial_swap_signature.scalar(
                        self.secp).negate(self.secp))

            public_lock = self.secret_lock.to_public_key(self.secp)
            assert self.public_lock == public_lock, "Invalid secret lock, this should never happen"

            if self.is_ether_swap():
                self.claim = self.secp.sign_recoverable(
                    self.secret_lock, bytearray([0] * 32))
        else:
            swap_input = Input(OutputFeatures.DEFAULT_OUTPUT, self.commit)
            public_swap_nonce_sum = PublicKey.from_combination(
                self.secp,
                [self.public_swap_nonce, self.foreign_public_swap_nonce])

            swap_signature = aggsig.add_partials(self.secp, [
                self.partial_swap_signature,
                self.foreign_partial_swap_signature
            ], public_swap_nonce_sum)

            assert aggsig.verify(
                self.secp, swap_signature, self.public_swap_excess,
                self.swap_fee_amount,
                self.swap_lock_height), "Unable to verify swap signature"

            swap_kernel = Kernel(0, self.swap_fee_amount,
                                 self.swap_lock_height, None, None)
            self.swap_tx = Transaction([swap_input], [self.swap_output],
                                       [swap_kernel], self.swap_offset)
            swap_kernel.excess = self.swap_tx.sum_commitments(self.secp)
            swap_kernel.excess_signature = swap_signature
            assert self.swap_tx.verify_kernels(
                self.secp), "Unable to verify swap kernel"
예제 #9
0
    def receive(self, dct: dict):
        if self.stage is None:
            if self.role == Role.BUYER:
                dct['time_start'] = int(time())

                self.wallet = Wallet.open(self.secp, dct['wallet'])

                # Add 'foreign_' prefix to some keys
                dct.update({
                    "foreign_partial_commit":
                    dct['partial_commit'],
                    "foreign_public_nonce":
                    dct['public_nonce'],
                    "foreign_public_refund_nonce":
                    dct['public_refund_nonce']
                })

                dct.pop("partial_commit", None)
                dct.pop("public_nonce", None)
                dct.pop("public_refund_nonce", None)

                # Partial multisig output
                self.partial_child, self.partial_entry = self.wallet.create_output(
                    dct['grin_amount'])
                self.partial_entry.mark_locked()

                self.nonce = SecretKey.random(self.secp)
                self.refund_nonce = SecretKey.random(self.secp)

                self.secret_lock = SecretKey.random(self.secp)
                self.public_lock = self.secret_lock.to_public_key(self.secp)

                if dct['swap_currency'] == "BTC":
                    self.btc_lock_time = int(time() + 24 * 60 * 60)
                    self.btc_refund_key = SecretKey.random(self.secp)
                    self.public_btc_refund_key = self.btc_refund_key.to_public_key(
                        self.secp)

                self.load(dct)
                if self.is_bitcoin_swap():
                    self.btc_lock_address = self.calculate_btc_lock_address()
                self.wallet.save()
            else:
                raise Exception("This stage doesn't expect an input file")
        elif self.stage == Stage.INIT:
            self.stage = Stage.SIGN
            self.foreign_t_1 = PublicKey.from_hex(self.secp,
                                                  dct['t_1'].encode())
            self.foreign_t_2 = PublicKey.from_hex(self.secp,
                                                  dct['t_2'].encode())
            if self.role == Role.SELLER:
                self.foreign_partial_commit = Commitment.from_hex(
                    self.secp, dct['partial_commit'].encode())
                self.foreign_public_nonce = PublicKey.from_hex(
                    self.secp, dct['public_nonce'].encode())
                self.foreign_public_refund_nonce = PublicKey.from_hex(
                    self.secp, dct['public_refund_nonce'].encode())
                self.public_lock = PublicKey.from_hex(
                    self.secp, dct['public_lock'].encode())
                if self.is_bitcoin_swap():
                    self.btc_lock_time = int(dct['btc_lock_time'])
                    self.public_btc_refund_key = PublicKey.from_hex(
                        self.secp, dct['public_btc_refund_key'])
                    self.btc_lock_address = self.calculate_btc_lock_address()
                if self.is_ether_swap():
                    self.eth_address_lock = ethereum_address(
                        self.secp, self.public_lock).decode()
                    self.eth_contract_address = dct['eth_contract_address']
                self.commit = self.secp.commit_sum([
                    self.foreign_partial_commit,
                    self.wallet.commit(self.partial_entry)
                ], [])
                self.foreign_partial_signature = Signature.from_hex(
                    dct['partial_signature'].encode())
                self.foreign_partial_refund_signature = Signature.from_hex(
                    dct['partial_refund_signature'].encode())
            else:
                self.foreign_tau_x = SecretKey.from_hex(
                    self.secp, dct['tau_x'].encode())
        elif self.stage == Stage.SIGN:
            self.stage = Stage.LOCK
            if self.role == Role.SELLER:
                self.range_proof = RangeProof.from_hex(
                    dct['range_proof'].encode())
            else:
                self.tx_height = dct['tx_height']
                self.foreign_public_swap_nonce = PublicKey.from_hex(
                    self.secp, dct['public_swap_nonce'].encode())
        elif self.stage == Stage.LOCK:
            self.stage = Stage.SWAP
            if self.role == Role.SELLER:
                self.foreign_public_swap_nonce = PublicKey.from_hex(
                    self.secp, dct['public_swap_nonce'].encode())
                self.swap_fee_amount = int(dct['swap_fee_amount'])
                self.swap_lock_height = int(dct['swap_lock_height'])
                self.swap_output = Output.from_dict(self.secp,
                                                    dct['swap_output'], True)
                self.swap_offset = BlindingFactor.from_hex(
                    dct['swap_offset'].encode())
                self.foreign_partial_swap_adaptor = Signature.from_hex(
                    dct['partial_swap_adaptor'])
            else:
                self.foreign_partial_swap_signature = Signature.from_hex(
                    dct['partial_swap_signature'])
        elif self.stage == Stage.SWAP:
            self.stage = Stage.DONE
            if self.role == Role.SELLER:
                self.foreign_partial_swap_signature = Signature.from_hex(
                    dct['partial_swap_signature'])
        else:
            raise Exception("Invalid stage")
예제 #10
0
    def load(self, dct=None):
        seller = self.role == Role.SELLER
        buyer = not seller

        from_file = dct is None
        if from_file:
            f = open(absolute(self.swap_file), "r")
            dct = json.loads(f.read())
            f.close()

        self.stage = Stage(dct['stage'])
        if self.wallet is None:
            self.wallet = Wallet.open(self.secp, dct['wallet'])
        self.time_start = int(dct['time_start'])
        self.grin_amount = int(dct['grin_amount'])
        self.swap_currency = dct['swap_currency']
        self.swap_amount = int(dct['swap_amount'])
        if seller or self.is_ether_swap():
            self.swap_receive_address = dct['swap_receive_address']
        self.lock_height = int(dct['lock_height'])
        self.refund_lock_height = int(dct['refund_lock_height'])
        self.inputs = [
            Input.from_dict(self.secp, x, True) for x in dct['inputs']
        ]
        self.fee_amount = int(dct['fee_amount'])
        self.refund_fee_amount = int(dct['refund_fee_amount'])
        self.change_output = Output.from_dict(self.secp, dct['change_output'],
                                              True)
        if from_file:
            self.partial_entry = self.wallet.get_output(dct['partial_entry'])
            self.partial_child = self.wallet.derive_from_entry(
                self.partial_entry)
        self.partial_commit = self.wallet.commit_with_child_key(
            0, self.partial_child)
        self.offset = BlindingFactor.from_hex(dct['offset'].encode())
        self.refund_output = Output.from_dict(self.secp, dct['refund_output'],
                                              True)
        self.refund_offset = BlindingFactor.from_hex(
            dct['refund_offset'].encode())
        if from_file:
            self.nonce = SecretKey.from_hex(self.secp, dct['nonce'].encode())
            self.refund_nonce = SecretKey.from_hex(
                self.secp, dct['refund_nonce'].encode())
        self.public_nonce = self.nonce.to_public_key(self.secp)
        self.public_refund_nonce = self.refund_nonce.to_public_key(self.secp)

        if seller:
            if self.is_bitcoin_swap():
                self.swap_cosign = SecretKey.from_hex(
                    self.secp, dct['swap_cosign'].encode())
            self.input_entries = [
                self.wallet.get_output(x) for x in dct['input_entries']
            ]
            self.input_amount = sum(x.value for x in self.input_entries)
            self.change_amount = self.input_amount - self.grin_amount - self.fee_amount
            self.change_entry = self.wallet.get_output(dct['change_entry'])
            self.change_child = self.wallet.derive_from_entry(
                self.change_entry)
            self.refund_entry = self.wallet.get_output(dct['refund_entry'])
            self.refund_child = self.wallet.derive_from_entry(
                self.refund_entry)
        else:
            if from_file:
                self.secret_lock = SecretKey.from_hex(
                    self.secp, dct['secret_lock'].encode())
                if self.is_bitcoin_swap():
                    self.btc_refund_key = SecretKey.from_hex(
                        self.secp, dct['btc_refund_key'].encode())

        if self.is_bitcoin_swap():
            self.public_swap_cosign = self.swap_cosign.to_public_key(self.secp) if seller else \
                PublicKey.from_hex(self.secp, dct['public_swap_cosign'].encode())

        if self.stage >= Stage.SIGN or buyer:
            self.foreign_partial_commit = Commitment.from_hex(
                self.secp, dct['foreign_partial_commit'].encode())
            self.foreign_public_nonce = PublicKey.from_hex(
                self.secp, dct['foreign_public_nonce'].encode())
            self.foreign_public_refund_nonce = PublicKey.from_hex(
                self.secp, dct['foreign_public_refund_nonce'].encode())
            if from_file:
                self.public_lock = PublicKey.from_hex(
                    self.secp, dct['public_lock'].encode())
                if self.is_bitcoin_swap():
                    self.public_btc_refund_key = self.btc_refund_key.to_public_key(self.secp) if buyer else \
                        PublicKey.from_hex(self.secp, dct['public_btc_refund_key'].encode())

            if self.is_ether_swap():
                self.eth_address_lock = ethereum_address(
                    self.secp, self.public_lock).decode()

            self.commit = self.secp.commit_sum([self.foreign_partial_commit,
                                                self.wallet.commit(self.partial_entry)], []) if not from_file else \
                Commitment.from_hex(self.secp, dct['commit'].encode())

        if self.stage >= Stage.SIGN or (buyer and from_file):
            self.public_excess = PublicKey.from_hex(
                self.secp, dct['public_excess'].encode())
            self.public_refund_excess = PublicKey.from_hex(
                self.secp, dct['public_refund_excess'].encode())
            if self.is_bitcoin_swap():
                self.btc_lock_time = int(dct['btc_lock_time'])
                self.btc_lock_address = Address.from_base58check(
                    dct['btc_lock_address'].encode())
            if self.is_ether_swap():
                self.eth_contract_address = dct['eth_contract_address']
            self.partial_signature = Signature.from_hex(
                dct['partial_signature'].encode())
            self.partial_refund_signature = Signature.from_hex(
                dct['partial_refund_signature'].encode())
            self.t_1 = PublicKey.from_hex(self.secp, dct['t_1'].encode())
            self.t_2 = PublicKey.from_hex(self.secp, dct['t_2'].encode())

        if self.stage >= Stage.SIGN:
            self.foreign_t_1 = PublicKey.from_hex(self.secp,
                                                  dct['foreign_t_1'].encode())
            self.foreign_t_2 = PublicKey.from_hex(self.secp,
                                                  dct['foreign_t_2'].encode())
            if seller:
                self.tau_x = SecretKey.from_hex(self.secp,
                                                dct['tau_x'].encode())
                self.foreign_partial_signature = Signature.from_hex(
                    dct['foreign_partial_signature'].encode())
                self.foreign_partial_refund_signature = Signature.from_hex(
                    dct['foreign_partial_refund_signature'].encode())
                if self.is_bitcoin_swap():
                    self.btc_output_points = [
                        OutputPoint.from_hex(x.encode())
                        for x in dct['btc_output_points']
                    ]
            else:
                self.foreign_tau_x = SecretKey.from_hex(
                    self.secp, dct['foreign_tau_x'].encode())

        if self.stage >= Stage.LOCK or (self.stage == Stage.SIGN and buyer):
            self.range_proof = RangeProof.from_hex(dct['range_proof'].encode())

        if self.stage >= Stage.LOCK:
            self.tx_height = dct['tx_height']
            self.swap_nonce = SecretKey.from_hex(self.secp,
                                                 dct['swap_nonce'].encode())
            self.public_swap_nonce = self.swap_nonce.to_public_key(self.secp)
            if buyer:
                self.swap_entry = self.wallet.get_output(dct['swap_entry'])
                self.swap_child = self.wallet.derive_from_entry(
                    self.swap_entry)
                self.partial_swap_adaptor = Signature.from_hex(
                    dct['partial_swap_adaptor'].encode())

        if (buyer and self.stage >= Stage.LOCK) or (seller and
                                                    self.stage >= Stage.SWAP):
            self.foreign_public_swap_nonce = PublicKey.from_hex(
                self.secp, dct['foreign_public_swap_nonce'].encode())
            self.swap_fee_amount = int(dct['swap_fee_amount'])
            self.swap_lock_height = int(dct['swap_lock_height'])
            self.swap_output = Output.from_dict(self.secp, dct['swap_output'],
                                                True)
            self.swap_offset = BlindingFactor.from_hex(
                dct['swap_offset'].encode())
            self.public_swap_excess = PublicKey.from_hex(
                self.secp, dct['public_swap_excess'].encode())
            self.partial_swap_signature = Signature.from_hex(
                dct['partial_swap_signature'].encode())

        if seller and self.stage >= Stage.SWAP:
            self.foreign_partial_swap_adaptor = Signature.from_hex(
                dct['foreign_partial_swap_adaptor'].encode())
예제 #11
0
    def finalize_swap(self):
        seller = self.role == Role.SELLER
        assert (seller and self.stage == Stage.DONE) or (
            not seller and self.stage == Stage.SWAP), "Incorrect stage"

        if seller:
            self.secret_lock = self.foreign_partial_swap_adaptor.scalar(
                self.secp).add(
                    self.secp,
                    self.foreign_partial_swap_signature.scalar(
                        self.secp).negate(self.secp))

            public_lock = self.secret_lock.to_public_key(self.secp)
            assert self.public_lock == public_lock, "Invalid secret lock, this should never happen"

            if self.is_bitcoin_swap():
                tx = BitcoinTransaction(2, [], [], int(time()))
                input_script = self.generate_btc_script()
                for output_point in self.btc_output_points:
                    tx.add_input(
                        BitcoinInput(output_point.txid, output_point.index,
                                     input_script, bytearray(), None))
                output = BitcoinOutput(
                    1,
                    Script.p2(
                        Address.from_base58check(
                            self.swap_receive_address.encode())))
                tx.add_output(output)
                tx_size = len(tx.to_bytearray()) + 270 * len(
                    self.btc_output_points)  # estimate total tx size
                fee = 2 * tx_size  # 2 sat/B
                output.value = self.swap_amount - fee
                for i in range(len(tx.inputs)):
                    signature_a = tx.raw_signature(self.secp, i,
                                                   self.swap_cosign)
                    signature_b = tx.raw_signature(self.secp, i,
                                                   self.secret_lock)
                    prev_script = self.generate_btc_script()

                    script_sig = bytearray()
                    script_sig.append(OP_FALSE)
                    script_sig.extend(script_write_bytes(len(signature_a)))
                    script_sig.extend(signature_a)
                    script_sig.extend(script_write_bytes(len(signature_b)))
                    script_sig.extend(signature_b)
                    script_sig.append(OP_FALSE)
                    script_sig.extend(script_write_bytes(len(prev_script)))
                    script_sig.extend(prev_script)
                    tx.inputs[i].script_sig = script_sig
                self.claim = hexlify(tx.to_bytearray())

            if self.is_ether_swap():
                self.claim = self.secp.sign_recoverable(
                    self.secret_lock, bytearray([0] * 32))
        else:
            swap_input = Input(OutputFeatures.DEFAULT_OUTPUT, self.commit)
            public_swap_nonce_sum = PublicKey.from_combination(
                self.secp,
                [self.public_swap_nonce, self.foreign_public_swap_nonce])

            swap_signature = aggsig.add_partials(self.secp, [
                self.partial_swap_signature,
                self.foreign_partial_swap_signature
            ], public_swap_nonce_sum)

            assert aggsig.verify(
                self.secp, swap_signature, self.public_swap_excess,
                self.swap_fee_amount,
                self.swap_lock_height), "Unable to verify swap signature"

            swap_kernel = Kernel(0, self.swap_fee_amount,
                                 self.swap_lock_height, None, None)
            self.swap_tx = Transaction([swap_input], [self.swap_output],
                                       [swap_kernel], self.swap_offset)
            swap_kernel.excess = self.swap_tx.sum_commitments(self.secp)
            swap_kernel.excess_signature = swap_signature
            assert self.swap_tx.verify_kernels(
                self.secp), "Unable to verify swap kernel"
예제 #12
0
    def fill_signatures(self):
        seller = self.role == Role.SELLER
        assert (not seller and self.stage == Stage.INIT) or (
            seller and self.stage == Stage.SIGN), "Incorrect stage"

        # Public (total) excess
        pos = [
            self.commit, self.change_output.commit,
            self.secp.commit_value(self.fee_amount)
        ]
        neg = [x.commit for x in self.inputs]
        neg.append(self.secp.commit(0, self.offset))
        self.public_excess = self.secp.commit_sum(pos,
                                                  neg).to_public_key(self.secp)

        # Partial excess
        blind_sum = BlindSum()
        blind_sum.add_child_key(self.partial_child)
        if seller:
            blind_sum.add_child_key(self.change_child)
            for entry in self.input_entries:
                blind_sum.sub_child_key(self.wallet.derive_from_entry(entry))
            blind_sum.sub_blinding_factor(self.offset)
        excess = self.wallet.chain.blind_sum(blind_sum).to_secret_key(
            self.secp)

        # Partial signature
        public_nonce_sum = PublicKey.from_combination(
            self.secp, [self.public_nonce, self.foreign_public_nonce])
        self.partial_signature = aggsig.calculate_partial(
            self.secp, excess, self.nonce, self.public_excess,
            public_nonce_sum, self.fee_amount, self.lock_height)

        # First step of multi party bullet proof
        proof_builder = TwoPartyBulletProof(
            self.secp, self.partial_child.key,
            self.foreign_partial_commit.to_public_key(self.secp),
            self.grin_amount, self.commit)
        self.t_1, self.t_2 = proof_builder.round_1()

        if seller:
            proof_builder.fill_round_1(self.foreign_t_1, self.foreign_t_2)
            self.tau_x = proof_builder.round_2()

        # Public (total) refund excess
        pos = [
            self.refund_output.commit,
            self.secp.commit_value(self.refund_fee_amount)
        ]
        neg = [self.commit, self.secp.commit(0, self.refund_offset)]
        self.public_refund_excess = self.secp.commit_sum(
            pos, neg).to_public_key(self.secp)

        # Partial refund excess
        refund_blind_sum = BlindSum()
        refund_blind_sum.sub_child_key(self.partial_child)
        if seller:
            refund_blind_sum.add_child_key(self.refund_child)
            refund_blind_sum.sub_blinding_factor(self.refund_offset)
        refund_excess = self.wallet.chain.blind_sum(
            refund_blind_sum).to_secret_key(self.secp)

        # Partial refund signature
        public_refund_nonce_sum = PublicKey.from_combination(
            self.secp,
            [self.public_refund_nonce, self.foreign_public_refund_nonce])
        self.partial_refund_signature = aggsig.calculate_partial(
            self.secp, refund_excess, self.refund_nonce,
            self.public_refund_excess, public_refund_nonce_sum,
            self.refund_fee_amount, self.refund_lock_height)
def test_public_key():
    secp = Secp256k1(None, FLAG_ALL)

    # (de)serialization
    secret_key = SecretKey.random(secp)
    public_key = secret_key.to_public_key(secp)
    public_key_2 = PublicKey.from_bytearray(secp,
                                            public_key.to_bytearray(secp))
    assert public_key == public_key_2

    # (a+b)*G = a*G + b*G
    secret_key_a = SecretKey.random(secp)
    secret_key_b = SecretKey.random(secp)
    secret_key_a_b = secret_key_a.add(secp, secret_key_b)
    public_key_a = secret_key_a.to_public_key(secp)
    public_key_b = secret_key_b.to_public_key(secp)
    public_key_a_b = secret_key_a_b.to_public_key(secp)
    public_key_a_b_2 = PublicKey.from_combination(secp,
                                                  [public_key_a, public_key_b])
    public_key_a_b_3 = public_key_a.add_scalar(secp, secret_key_b)
    assert public_key_a_b == public_key_a_b_2
    assert public_key_a_b == public_key_a_b_3

    # (ab)*G = a(b*G) = b(a*G)
    secret_key_a = SecretKey.random(secp)
    secret_key_b = SecretKey.random(secp)
    secret_key_ab = secret_key_a.mul(secp, secret_key_b)
    public_key_ab = secret_key_ab.to_public_key(secp)
    public_key_ab_2 = secret_key_a.to_public_key(secp)
    public_key_ab_2.mul_assign(secp, secret_key_b)
    public_key_ab_3 = secret_key_b.to_public_key(secp)
    public_key_ab_3.mul_assign(secp, secret_key_a)
    assert public_key_ab == public_key_ab_2
    assert public_key_ab == public_key_ab_3

    # (c(a+b))*G = c(a*G) + c(b*G)
    secret_key_a = SecretKey.random(secp)
    secret_key_b = SecretKey.random(secp)
    secret_key_c = SecretKey.random(secp)
    secret_key_ca_b = secret_key_a.add(secp, secret_key_b)
    secret_key_ca_b.mul_assign(secp, secret_key_c)
    public_key_ca_b = secret_key_ca_b.to_public_key(secp)
    public_key_ca = secret_key_a.to_public_key(secp)
    public_key_ca.mul_assign(secp, secret_key_c)
    public_key_cb = secret_key_b.to_public_key(secp)
    public_key_cb.mul_assign(secp, secret_key_c)
    public_key_ca_cb = public_key_ca.add(secp, public_key_cb)
    assert public_key_ca_b == public_key_ca_cb

    # (a+b+c)*G = a*G + b*G + c*G
    secret_key_a = SecretKey.random(secp)
    secret_key_b = SecretKey.random(secp)
    secret_key_c = SecretKey.random(secp)
    secret_key_a_b_c = secret_key_a.add(secp, secret_key_b)
    secret_key_a_b_c.add_assign(secp, secret_key_c)
    public_key_a_b_c = secret_key_a_b_c.to_public_key(secp)
    public_key_a = secret_key_a.to_public_key(secp)
    public_key_b = secret_key_b.to_public_key(secp)
    public_key_c = secret_key_c.to_public_key(secp)
    public_key_a_b_c_2 = PublicKey.from_combination(
        secp, [public_key_a, public_key_b, public_key_c])
    assert public_key_a_b_c == public_key_a_b_c_2
예제 #14
0
 def from_bytearray(secp: Secp256k1, data: bytearray):
     assert len(data) == 78
     return ExtendedPublicKey(data[:4], data[4], Fingerprint.from_bytearray(data[5:9]),
                              ChildNumber.from_bytearray(data[9:13]), PublicKey.from_bytearray(secp, data[45:78]),
                              ChainCode.from_bytearray(data[13:45]))