def test_two_party_proof():
    secp = Secp256k1(None, FLAG_ALL)
    secret_key_a = SecretKey.random(secp)
    public_key_a = secret_key_a.to_public_key(secp)
    child_key_a = ChildKey(0, Identifier.random(), Identifier.random(),
                           secret_key_a)
    secret_key_b = SecretKey.random(secp)
    public_key_b = secret_key_b.to_public_key(secp)
    child_key_b = ChildKey(0, Identifier.random(), Identifier.random(),
                           secret_key_b)
    amount = randint(1, 999999)
    commit = secp.commit_sum(
        [secp.commit(amount, secret_key_a),
         secp.commit(0, secret_key_b)], [])
    tpp_a = TwoPartyBulletProof(secp, child_key_a, public_key_b, amount,
                                commit)
    tpp_b = TwoPartyBulletProof(secp, child_key_b, public_key_a, amount,
                                commit)
    t_1_a, t_2_a = tpp_a.round_1()
    t_1_b, t_2_b = tpp_b.round_1()
    tpp_a.fill_round_1(t_1_b, t_2_b)
    tpp_b.fill_round_1(t_1_a, t_2_a)
    tau_x_a = tpp_a.round_2()
    tau_x_b = tpp_b.round_2()
    tpp_a.fill_round_2(tau_x_b)
    tpp_b.fill_round_2(tau_x_a)
    proof_a = tpp_a.finalize()
    assert secp.verify_bullet_proof(commit, proof_a, bytearray())
    proof_b = tpp_b.finalize()
    assert proof_a == proof_b
def test_partial_sig():
    secp = Secp256k1(None, FLAG_ALL)
    excess = SecretKey.random(secp)
    public_excess = excess.to_public_key(secp)
    nonce = SecretKey.random(secp)
    public_key_sum = SecretKey.random(secp).to_public_key(secp)
    public_nonce_sum = SecretKey.random(secp).to_public_key(secp)
    fee = randint(1, 999999)
    lock_height = randint(1, 999999)
    sig = aggsig.calculate_partial(secp, excess, nonce, public_key_sum,
                                   public_nonce_sum, fee, lock_height)

    assert aggsig.verify_partial(secp, sig, public_excess, public_key_sum,
                                 public_nonce_sum, fee, lock_height)
    rnd_sig = Signature(bytearray(urandom(64)))
    assert not aggsig.verify_partial(secp, rnd_sig, public_excess,
                                     public_key_sum, public_nonce_sum, fee,
                                     lock_height)
    public_rnd = SecretKey.random(secp).to_public_key(secp)
    assert not aggsig.verify_partial(secp, sig, public_rnd, public_key_sum,
                                     public_nonce_sum, fee, lock_height)
    assert not aggsig.verify_partial(secp, sig, public_excess, public_rnd,
                                     public_nonce_sum, fee, lock_height)
    assert not aggsig.verify_partial(secp, sig, public_excess, public_key_sum,
                                     public_rnd, fee, lock_height)
    assert not aggsig.verify_partial(secp, sig, public_excess, public_key_sum,
                                     public_nonce_sum, 0, lock_height)
    assert not aggsig.verify_partial(secp, sig, public_excess, public_key_sum,
                                     public_nonce_sum, fee, 0)
Пример #3
0
    def select_inputs(self):
        assert self.stage is None, "Incorrect stage"
        assert self.role == Role.SELLER, "Incorrect role"

        self.stage = Stage.INIT

        if self.is_bitcoin_swap():
            # Generate a key that will co-sign the BTC multisig
            self.swap_cosign = SecretKey.random(self.secp)
            self.public_swap_cosign = self.swap_cosign.to_public_key(self.secp)

        # Inputs
        self.input_entries = self.wallet.select_outputs(
            self.grin_amount + tx_fee(1, 2, MILLI_GRIN_UNIT) + 1)
        self.inputs = []
        for entry in self.input_entries:
            entry.mark_locked()
            input = self.wallet.entry_to_input(entry)
            self.inputs.append(input)
        self.fee_amount = tx_fee(len(self.input_entries), 2, MILLI_GRIN_UNIT)
        self.refund_fee_amount = tx_fee(1, 1, MILLI_GRIN_UNIT)
        self.input_amount = sum(x.value for x in self.input_entries)
        self.change_amount = self.input_amount - self.grin_amount - self.fee_amount

        # Change output
        self.change_child, self.change_entry = self.wallet.create_output(
            self.change_amount)
        self.change_entry.mark_locked()
        self.change_output = self.wallet.entry_to_output(self.change_entry)

        # Partial multisig output
        self.partial_child, self.partial_entry = self.wallet.create_output(
            self.grin_amount)
        self.partial_entry.mark_locked()
        self.partial_commit = self.wallet.commit_with_child_key(
            0, self.partial_child)

        # Offset
        self.offset = BlindingFactor.from_secret_key(
            SecretKey.random(self.secp))

        # Refund output
        refund_amount = self.grin_amount - self.refund_fee_amount
        self.refund_child, self.refund_entry = self.wallet.create_output(
            refund_amount)
        self.refund_output = self.wallet.entry_to_output(self.refund_entry)

        # Refund offset
        self.refund_offset = BlindingFactor.from_secret_key(
            SecretKey.random(self.secp))

        # Nonces
        self.nonce = SecretKey.random(self.secp)
        self.public_nonce = self.nonce.to_public_key(self.secp)
        self.refund_nonce = SecretKey.random(self.secp)
        self.public_refund_nonce = self.refund_nonce.to_public_key(self.secp)

        self.wallet.save()
Пример #4
0
    def prepare_swap(self):
        assert self.role == Role.BUYER and self.stage == Stage.LOCK, "Incorrect stage"

        self.swap_nonce = SecretKey.random(self.secp)
        self.public_swap_nonce = self.swap_nonce.to_public_key(self.secp)
        self.swap_fee_amount = tx_fee(1, 1, MILLI_GRIN_UNIT)
        self.swap_lock_height = self.lock_height + 1
        self.swap_child, self.swap_entry = self.wallet.create_output(
            self.grin_amount - self.swap_fee_amount)
        self.wallet.save()
        self.swap_offset = BlindingFactor.from_secret_key(
            SecretKey.random(self.secp))
        self.swap_output = self.wallet.entry_to_output(self.swap_entry)

        self.fill_swap_signatures()
def multi_party_proof(n):
    assert n > 1
    secp = Secp256k1(None, FLAG_ALL)
    mpps = []
    child_keys = []
    amount = randint(1, 999999)
    commit_sum = [secp.commit_value(amount)]
    common_nonce = SecretKey.random(secp)
    for i in range(n):
        child_keys.append(
            ChildKey(i, Identifier.random(), Identifier.random(),
                     SecretKey.random(secp)))
        child_key = child_keys[i]
        commit_sum.append(secp.commit(0, child_key.key))
    # Total commitment: sum xi*G + v*H
    commitment = secp.commit_sum(commit_sum, [])
    t_1s = []
    t_2s = []
    # Each party exports their T1 and T2
    for i in range(n):
        mpps.append(
            MultiPartyBulletProof(secp, child_keys[i], amount, commitment,
                                  common_nonce))
        t_1, t_2 = mpps[i].round_1()
        t_1s.append(t_1)
        t_2s.append(t_2)
    # Each party receives the other T1 and T2 values and adds it to their own
    for i in range(n):
        for j in range(n):
            if i != j:
                mpps[i].fill_round_1(t_1s[j], t_2s[j])
    tau_xs = []
    # Each party exports their tau_x
    for i in range(n):
        tau_xs.append(mpps[i].round_2())
    # One party receives the other tau_x values and adds it to their own
    # In this test we simulate each party calculating the proof
    for i in range(n):
        for j in range(n):
            if i != j:
                mpps[i].fill_round_2(tau_xs[j])
    proofs = []
    for i in range(n):
        proofs.append(mpps[i].finalize())
        assert secp.verify_bullet_proof(commitment, proofs[i], bytearray())
    for i in range(n - 1):
        assert proofs[i + 1] == proofs[0]
Пример #6
0
def create_nonce(secp: Secp256k1, chain_code: ChainCode,
                 commit: Commitment) -> SecretKey:
    return SecretKey.from_bytearray(
        secp,
        bytearray(
            blake2b(bytes(chain_code.chain_code),
                    digest_size=32,
                    key=bytes(commit.to_bytearray(secp))).digest()))
Пример #7
0
 def sign(self, secp: Secp256k1, i: int, secret_key: SecretKey):
     script_sig = bytearray()
     signature = self.raw_signature(secp, i, secret_key)
     script_sig.extend(script_write_bytes(len(signature)))
     script_sig.extend(signature)
     public_key = secret_key.to_public_key(secp).to_bytearray(secp)
     script_sig.extend(script_write_bytes(len(public_key)))
     script_sig.extend(public_key)
     self.inputs[i].script_sig = script_sig
Пример #8
0
def post(handler: HTTPServerHandler):
    global secp, wallet, server
    try:
        length = handler.headers['Content-Length']
        length = 0 if length is None else int(length)
        raw = ""
        if length > 0:
            raw = handler.rfile.read(length).decode()
        f = open("simple_tx_receive.json", "w")
        f.write(raw)
        f.close()
        slate = Slate.from_dict(secp, json.loads(raw))

        print("Receive {} grin".format(slate.amount / GRIN_UNIT))

        # Output
        # n_outputs = min(100, slate.amount)
        n_outputs = 1
        blind_sum = BlindSum()
        output_child_key, output_entry = wallet.create_output(slate.amount-n_outputs+1)
        print("Generate output 0: {}".format(wallet.commit(output_entry)))
        print()
        blind_sum.add_child_key(output_child_key)
        slate.tx.add_output(secp, wallet.entry_to_output(output_entry))
        if n_outputs > 1:
            for i in range(n_outputs-1):
                output_child_key_loop, output_entry_loop = wallet.create_output(1)
                print("Generate output {}: {}".format(i + 1, wallet.commit(output_entry_loop)))
                blind_sum.add_child_key(output_child_key_loop)
                slate.tx.add_output(secp, wallet.entry_to_output(output_entry_loop))

        # Excess
        excess = wallet.chain.blind_sum(blind_sum).to_secret_key(secp)
        public_excess = excess.to_public_key(secp)
        print("Generated excess")

        # Nonce
        nonce = SecretKey.random(secp)
        public_nonce = nonce.to_public_key(secp)

        # Add participant data
        participant = ParticipantData(1, public_excess, public_nonce, None)
        slate.add_participant(participant)

        # After all participants published their nonce, calculate partial signature
        slate.partial_signature(secp, participant, excess, nonce)

        resp = json.dumps(slate.to_dict(secp))

        wallet.save()

        handler.json_response((resp + "\r\n").encode())

        print("Sent response")
    except Exception as e:
        print("Unable to parse slate: {}".format(e))
        handler.error_response()
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)
def test_proofs(create=False):
    secp = Secp256k1(None, FLAG_ALL)

    if create:
        dct = []
        for i in range(100):
            secret = SecretKey.random(secp)
            nonce = SecretKey.random(secp)
            amount = randint(1, 10000000000)
            proof = secp.bullet_proof(amount, secret, nonce, bytearray())
            dct.append({
                "secret": secret.to_hex().decode(),
                "nonce": nonce.to_hex().decode(),
                "amount": amount,
                "proof": proof.to_hex().decode()
            })
        f = open("proofs_new.json", "w")
        f.write(json.dumps(dct, indent=2))
        f.close()
        return

    f = open("tests/proofs.json", "r")
    dct = json.loads(f.read())
    f.close()

    test_count = 0
    test_equal_count = 0
    for test in dct:
        test_count += 1
        secret = SecretKey.from_hex(secp, test['secret'].encode())
        nonce = SecretKey.from_hex(secp, test['nonce'].encode())
        amount = test['amount']
        proof_target = RangeProof.from_hex(test['proof'].encode())
        proof = secp.bullet_proof(amount, secret, nonce, bytearray())
        commit = secp.commit(amount, secret)
        assert secp.verify_bullet_proof(
            commit, proof,
            bytearray()), "Proof {} fails to verify".format(test_count)
        if proof == proof_target:
            test_equal_count += 1

    assert test_count == test_equal_count, \
        "All proofs verify, but only {} out of {} proofs are the same".format(test_equal_count, test_count)
Пример #11
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()))
Пример #12
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)
Пример #13
0
    def ckd_public(self, secp: Secp256k1, hasher: Hasher, i: ChildNumber):
        if i.is_hardened():
            raise HardenedIndexError()

        hasher.init_sha512(self.chain_code.to_bytearray())
        hasher.append_sha512(self.public_key.to_bytearray(secp))
        hasher.append_sha512(i.to_bytearray())
        hash = hasher.result_sha512()
        key = SecretKey.from_bytearray(secp, hash[:32]).to_public_key(secp)
        key.add_assign(secp, self.public_key)

        return ExtendedPublicKey(self.network, self.depth + 1, self.fingerprint(secp, hasher),
                                 i, key, ChainCode.from_bytearray(hash[32:]))
Пример #14
0
 def ckd_secret(self, secp: Secp256k1, hasher: Hasher, i: ChildNumber):
     hasher.init_sha512(self.chain_code.to_bytearray())
     if i.is_normal():
         hasher.append_sha512(self.secret_key.to_public_key(secp).to_bytearray(secp))
     else:
         hasher.append_sha512(bytearray([0]))
         hasher.append_sha512(self.secret_key.to_bytearray())
     hasher.append_sha512(i.to_bytearray())
     hash = hasher.result_sha512()
     key = SecretKey.from_bytearray(secp, hash[:32])
     key.add_assign(secp, self.secret_key)
     return ExtendedSecretKey(self.network, self.depth + 1, self.fingerprint(secp, hasher),
                              i, key, ChainCode.from_bytearray(hash[32:]))
Пример #15
0
 def blind_sum(self, positives, negatives) -> SecretKey:
     keys = []
     for positive in positives:
         assert isinstance(positive, SecretKey)
         keys.append(ffi.new("char []", bytes(positive.key)))
     for negative in negatives:
         assert isinstance(negative, SecretKey)
         keys.append(ffi.new("char []", bytes(negative.key)))
     sum_key = ffi.new("char []", SECRET_KEY_SIZE)
     ret = lib.secp256k1_pedersen_blind_sum(self.ctx, sum_key, keys,
                                            len(keys), len(positives))
     assert ret, "Unable to sum blinding factors"
     return SecretKey.from_bytearray(
         self, bytearray(ffi.buffer(sum_key, SECRET_KEY_SIZE)))
Пример #16
0
 def bullet_proof_multisig_2(self, value: int, blind: SecretKey,
                             commit: Commitment, common_nonce: SecretKey,
                             nonce: SecretKey, t_1: PublicKey,
                             t_2: PublicKey,
                             extra_data: bytearray) -> SecretKey:
     scratch = lib.secp256k1_scratch_space_create(self.ctx, 256 * MAX_WIDTH)
     tau_x_ptr = ffi.new("char []", 32)
     blind_key = ffi.new("char []", bytes(blind.key))
     res = lib.secp256k1_bulletproof_rangeproof_prove(
         self.ctx, scratch, self.gens, ffi.NULL, ffi.NULL, tau_x_ptr,
         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 SecretKey.from_bytearray(self,
                                     bytearray(ffi.buffer(tau_x_ptr, 32)))
Пример #17
0
 def bullet_proof_multisig_3(self, value: int, blind: SecretKey,
                             commit: Commitment, common_nonce: SecretKey,
                             nonce: SecretKey, t_1: PublicKey,
                             t_2: PublicKey, tau_x: SecretKey,
                             extra_data: bytearray) -> RangeProof:
     scratch = lib.secp256k1_scratch_space_create(self.ctx, 256 * MAX_WIDTH)
     proof_ptr = ffi.new("char []", MAX_PROOF_SIZE)
     proof_len_ptr = ffi.new("size_t *", MAX_PROOF_SIZE)
     tau_x_ptr = ffi.new("char []", bytes(tau_x.to_bytearray()))
     blind_key = ffi.new("char []", bytes(blind.key))
     res = lib.secp256k1_bulletproof_rangeproof_prove(
         self.ctx, scratch, self.gens, proof_ptr, proof_len_ptr, tau_x_ptr,
         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)
     obj = RangeProof.from_bytearray(
         bytearray(ffi.buffer(proof_ptr, proof_len_ptr[0])))
     lib.secp256k1_scratch_space_destroy(scratch)
     assert res, "Unable to generate multisig bulletproof"
     return obj
Пример #18
0
 def from_bytearray(secp: Secp256k1, data: bytearray):
     assert len(data) == 78
     return ExtendedSecretKey(data[:4], data[4], Fingerprint.from_bytearray(data[5:9]),
                              ChildNumber.from_bytearray(data[9:13]), SecretKey.from_bytearray(secp, data[46:78]),
                              ChainCode.from_bytearray(data[13:45]))
Пример #19
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")
Пример #20
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())
Пример #21
0
 def empty(secp: Secp256k1, features: int, fee: int, lock_height: int):
     kernel = Kernel(features, fee, lock_height, None, None)
     return Transaction([], [], [kernel],
                        BlindingFactor.from_secret_key(
                            SecretKey.random(secp)))
Пример #22
0
def send(node_url: str):
    global secp, wallet
    send_amount = 1
    height = 33333
    lock_height = 33333
    features = 0
    dest_url = "http://127.0.0.1:17175"
    fluff = True
    n_outputs = 2

    secp = Secp256k1(None, FLAG_ALL)

    wallet = Wallet.open(secp, "wallet_1")

    print("Preparing to send {} grin to {}".format(send_amount / GRIN_UNIT, dest_url))

    input_entries = wallet.select_outputs(send_amount + tx_fee(1, n_outputs, MILLI_GRIN_UNIT))
    fee_amount = tx_fee(len(input_entries), n_outputs, MILLI_GRIN_UNIT)
    input_amount = sum(x.value for x in input_entries)
    change_amount = input_amount - send_amount - fee_amount

    print("Selected {} inputs".format(len(input_entries)))

    blind_sum = BlindSum()

    slate = Slate.blank(secp, 2, send_amount, height, features, fee_amount, lock_height)

    # Inputs
    for entry in input_entries:
        entry.mark_locked()
        blind_sum.sub_child_key(wallet.derive_from_entry(entry))
        slate.tx.add_input(secp, wallet.entry_to_input(entry))

    # Change output
    change_key, change_entry = wallet.create_output(change_amount)
    blind_sum.add_child_key(change_key)
    slate.tx.add_output(secp, wallet.entry_to_output(change_entry))

    # Excess
    blind_sum.sub_blinding_factor(slate.tx.offset)
    excess = wallet.chain.blind_sum(blind_sum).to_secret_key(secp)
    public_excess = excess.to_public_key(secp)

    # Nonce
    nonce = SecretKey.random(secp)
    public_nonce = nonce.to_public_key(secp)

    # Participant
    participant = ParticipantData(0, public_excess, public_nonce, None)
    slate.add_participant(participant)

    print("Sending slate to receiver..")

    req = urlopen(dest_url, json.dumps(slate.to_dict(secp)).encode(), 600)
    slate = Slate.from_dict(secp, json.loads(req.read().decode()))

    print("Received response, finishing transaction..")

    participant = slate.get_participant(0)
    slate.partial_signature(secp, participant, excess, nonce)
    slate.finalize(secp)

    tx_wrapper = {
        "tx_hex": slate.tx.to_hex(secp).decode()
    }

    print("Submitting to node..")

    urlopen("{}/v1/pool/push".format(node_url) + ("?fluff" if fluff else ""), json.dumps(tx_wrapper).encode(), 600)

    wallet.save()

    print("Transaction complete!")
Пример #23
0
 def commit_value(self, value: int) -> Commitment:
     blind = SecretKey()
     return self.commit(value, blind)
 def from_secret_key(key: SecretKey):
     return BlindingFactor.from_bytearray(key.to_bytearray())
Пример #25
0
 def new_master(secp: Secp256k1, hasher: Hasher, seed: bytearray):
     hasher.init_sha512(hasher.master_seed())
     hasher.append_sha512(seed)
     hash = hasher.result_sha512()
     return ExtendedSecretKey(hasher.network_secret(), 0, Fingerprint.default(), ChildNumber.from_normal_index(0),
                              SecretKey.from_bytearray(secp, hash[:32]), ChainCode.from_bytearray(hash[32:]))
 def to_secret_key(self, secp: Secp256k1) -> SecretKey:
     return SecretKey.from_bytearray(secp, self.to_bytearray())
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
 def from_secret_key(secp: Secp256k1, key: SecretKey):
     public = key.to_public_key(secp)
     return Identifier.from_public_key(secp, public)
def test_secret_key():
    secp = Secp256k1(None, FLAG_ALL)

    # (de)serialization
    key_a = SecretKey.random(secp)
    key_b = SecretKey.from_bytearray(secp, key_a.to_bytearray())
    assert key_a == key_b

    # Too short
    with raises(Exception):
        SecretKey.from_bytearray(secp,
                                 bytearray([0x01] * (SECRET_KEY_SIZE - 1)))

    # Too long
    with raises(Exception):
        SecretKey.from_bytearray(secp,
                                 bytearray([0x01] * (SECRET_KEY_SIZE + 1)))

    # Zero
    with raises(Exception):
        SecretKey.from_bytearray(secp, bytearray([0] * SECRET_KEY_SIZE))

    # Overflow
    with raises(Exception):
        SecretKey.from_bytearray(secp, bytearray([0xFF] * SECRET_KEY_SIZE))

    # Top of range
    SecretKey.from_bytearray(
        secp,
        bytearray([
            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
            0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48,
            0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x40
        ]))

    # One past top of range
    with raises(Exception):
        SecretKey.from_bytearray(
            secp,
            bytearray([
                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6,
                0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36,
                0x41, 0x41
            ]))

    # a=a
    key_a = SecretKey.from_bytearray(secp, bytearray([0xCB] * SECRET_KEY_SIZE))
    key_b = SecretKey.from_bytearray(secp, bytearray([0xCB] * SECRET_KEY_SIZE))
    assert key_a == key_b

    # a!=b
    key_b = SecretKey.from_bytearray(secp, bytearray([0xCC] * SECRET_KEY_SIZE))
    assert key_a != key_b

    # a+b
    key_a = SecretKey.from_bytearray(secp, bytearray([0xDD] * SECRET_KEY_SIZE))
    key_b = SecretKey.from_bytearray(secp, bytearray([0x02] * SECRET_KEY_SIZE))
    key_a.add_assign(secp, key_b)
    key_c = SecretKey.from_bytearray(secp, bytearray([0xDF] * SECRET_KEY_SIZE))
    assert key_a == key_c

    # a+b = b+a
    key_a = SecretKey.random(secp)
    key_b = SecretKey.random(secp)
    key_a_b = key_a.add(secp, key_b)
    key_b_a = key_b.add(secp, key_a)
    assert key_a_b == key_b_a

    # Key addition where sum > order (N-1+N-2=N-3)
    key_a = SecretKey.from_bytearray(
        secp,
        bytearray([
            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
            0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48,
            0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x40
        ]))
    key_b = SecretKey.from_bytearray(
        secp,
        bytearray([
            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
            0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48,
            0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3F
        ]))
    key_a.add_assign(secp, key_b)
    key_c = SecretKey.from_bytearray(
        secp,
        bytearray([
            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
            0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48,
            0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x3E
        ]))
    assert key_a == key_c

    # ab = ba
    key_a = SecretKey.random(secp)
    key_b = SecretKey.random(secp)
    key_ab = key_a.mul(secp, key_b)
    key_ba = key_b.mul(secp, key_a)
    assert key_ab == key_ba

    # c(a+b) = ca + cb
    key_a = SecretKey.random(secp)
    key_b = SecretKey.random(secp)
    key_c = SecretKey.random(secp)
    key_ca = key_a.mul(secp, key_c)
    key_cb = key_b.mul(secp, key_c)
    key_ca_b = key_a.add(secp, key_b)
    key_ca_b.mul_assign(secp, key_c)
    key_ca_cb = key_ca.add(secp, key_cb)
    assert key_ca_b == key_ca_cb