Example #1
0
 async def challenge(self, body, stream):
     challenge = body.get('params', {}).get('token')
     signed_challenge = TU.generate_signature(challenge,
                                              self.config.private_key)
     await self.write_result(
         stream, 'authenticate', {
             'peer': self.config.peer.to_dict(),
             'signed_challenge': signed_challenge
         }, body['id'])
Example #2
0
    async def create_relationship(self, bulletin_secret, username, to):
        config = self.config
        mongo = self.config.mongo

        if not bulletin_secret:
            return 'error: "bulletin_secret" missing', 400

        if not username:
            return 'error: "username" missing', 400

        if not to:
            return 'error: "to" missing', 400
        rid = TU.generate_rid(config, bulletin_secret)
        dup = mongo.db.blocks.find({'transactions.rid': rid})
        if dup.count():
            found_a = False
            found_b = False
            for txn in dup:
                if txn['public_key'] == config.public_key:
                    found_a = True
                if txn['public_key'] != config.public_key:
                    found_b = True
            if found_a and found_b:
                return json.dumps({
                    "success": False,
                    "status": "Already added"
                })

        miner_transactions = mongo.db.miner_transactions.find()
        mtxn_ids = []
        for mtxn in miner_transactions:
            for mtxninput in mtxn['inputs']:
                mtxn_ids.append(mtxninput['id'])

        checked_out_txn_ids = mongo.db.checked_out_txn_ids.find()
        for mtxn in checked_out_txn_ids:
            mtxn_ids.append(mtxn['id'])

        a = os.urandom(32).decode('latin1')
        dh_public_key = scalarmult_base(a).encode('latin1').hex()
        dh_private_key = a.encode('latin1').hex()

        transaction = await Transaction.generate(
            bulletin_secret=bulletin_secret,
            username=username,
            fee=0.00,
            public_key=config.public_key,
            dh_public_key=dh_public_key,
            private_key=config.private_key,
            dh_private_key=dh_private_key,
            outputs=[{
                'to': to,
                'value': 0
            }])
        return transaction
Example #3
0
    async def post(self):
        key_or_wif = self.get_secure_cookie("key_or_wif")
        if not key_or_wif and self.jwt.get('key_or_wif') != 'true':
            return self.render_as_json({'error': 'not authorized'})
        args = json.loads(self.request.body)
        if not args.get('uid'):
            return self.render_as_json({
                "error": True,
                "message": "no user account provided"
            })
        keyhash = hashlib.sha256(
            TU.generate_deterministic_signature(
                self.config, 'child_wallet').encode()).hexdigest()
        exkey = BIP32Key.fromExtendedKey(self.config.xprv)
        last_child_key = self.config.mongo.db.child_keys.find(
            {'signature': keyhash}, sort=[('inc', -1)])
        inc = last_child_key.count() + 1
        key = exkey.ChildKey(inc)
        child_key = BIP32Key.fromExtendedKey(key.ExtendedKey())
        child_key = child_key.ChildKey(inc)
        public_key = child_key.PublicKey().hex()
        address = str(
            P2PKHBitcoinAddress.from_pubkey(bytes.fromhex(public_key)))
        private_key = child_key.PrivateKey().hex()
        wif = self.to_wif(private_key)

        await self.config.mongo.async_db.child_keys.insert_one({
            'account':
            args.get('uid'),
            'inc':
            inc,
            'extended':
            child_key.ExtendedKey(),
            'public_key':
            public_key,
            'address':
            address,
            'private_key':
            private_key,
            'wif':
            wif,
            'signature':
            keyhash
        })
        return self.render_as_json({"address": address})
Example #4
0
 async def challenge(self, body, stream):
     self.ensure_protocol_version(body, stream)
     params = body.get('params', {})
     challenge = params.get('token')
     signed_challenge = TU.generate_signature(challenge,
                                              self.config.private_key)
     if stream.peer.protocol_version > 1:
         await self.write_params(
             stream, 'authenticate', {
                 'peer': self.config.peer.to_dict(),
                 'signed_challenge': signed_challenge
             })
     else:
         await self.write_result(
             stream, 'authenticate', {
                 'peer': self.config.peer.to_dict(),
                 'signed_challenge': signed_challenge
             }, body['id'])
Example #5
0
    async def generate(
        cls,
        transactions=None,
        public_key=None,
        private_key=None,
        force_version=None,
        index=0,
        force_time=None,
        prev_hash=None,
        nonce=None,
        target=CHAIN.MAX_TARGET
    ):
        config = get_config()
        app_log = getLogger("tornado.application")
        if force_version is None:
            version = CHAIN.get_version_for_height(index)
        else:
            version = force_version
        if force_time:
            xtime = str(int(force_time))
        else:
            xtime = str(int(time.time()))
        index = int(index)
        if index == 0:
            prev_hash = ''
        elif prev_hash is None and index != 0:
            prev_hash = LatestBlock.block.hash
        transactions = transactions or []

        transaction_objs = []
        fee_sum = 0.0
        used_sigs = []
        used_inputs = {}
        for txn in transactions:
            try:
                if isinstance(txn, Transaction):
                    transaction_obj = txn
                else:
                    transaction_obj = Transaction.from_dict(txn)

                if transaction_obj.transaction_signature in used_sigs:
                    print('duplicate transaction found and removed')
                    continue

                await transaction_obj.verify()
                used_sigs.append(transaction_obj.transaction_signature)
            except:
                raise InvalidTransactionException("invalid transactions")
            try:
                if int(index) > CHAIN.CHECK_TIME_FROM and (int(transaction_obj.time) > int(xtime) + CHAIN.TIME_TOLERANCE):
                    config.mongo.db.miner_transactions.remove({'id': transaction_obj.transaction_signature}, multi=True)
                    app_log.debug("Block embeds txn too far in the future {} {}".format(xtime, transaction_obj.time))
                    continue
                
                if transaction_obj.inputs:
                    failed = False
                    used_ids_in_this_txn = []
                    for x in transaction_obj.inputs:
                        if config.BU.is_input_spent(x.id, transaction_obj.public_key):
                            failed = True
                        if x.id in used_ids_in_this_txn:
                            failed = True
                        if (x.id, transaction_obj.public_key) in used_inputs:
                            failed = True
                        used_inputs[(x.id, transaction_obj.public_key)] = transaction_obj
                        used_ids_in_this_txn.append(x.id)
                    if failed:
                        continue

                transaction_objs.append(transaction_obj)

                fee_sum += float(transaction_obj.fee)
            except Exception as e:
                await config.mongo.async_db.miner_transactions.delete_many({'id': transaction_obj.transaction_signature})
                config.app_log.debug('Exception {}'.format(e))
                continue

        block_reward = CHAIN.get_block_reward(index)
        coinbase_txn = await Transaction.generate(
            public_key=public_key,
            private_key=private_key,
            outputs=[{
                'value': block_reward + float(fee_sum),
                'to': str(P2PKHBitcoinAddress.from_pubkey(bytes.fromhex(public_key)))
            }],
            coinbase=True
        )
        transaction_objs.append(coinbase_txn)

        transactions = transaction_objs
        block = await cls.init_async(
            version=version,
            block_time=xtime,
            block_index=index,
            prev_hash=prev_hash,
            transactions=transactions,
            public_key=public_key,
            target=target
        )
        txn_hashes = block.get_transaction_hashes()
        block.set_merkle_root(txn_hashes)
        block.target = target
        block.header = block.generate_header()
        if nonce:
            block.nonce = str(nonce)
            block.hash = block.generate_hash_from_header(
                block.index,
                block.header,
                str(block.nonce)
            )
            block.signature = TU.generate_signature(block.hash, private_key)
        return block
Example #6
0
    async def post(self):
        key_or_wif = self.get_secure_cookie("key_or_wif")
        if not key_or_wif and self.jwt.get('key_or_wif') != 'true':
            return self.render_as_json({'error': 'not authorized'})
        config = self.config
        mongo = self.config.mongo
        body = json.loads(self.request.body.decode('utf-8'))
        try:
            fg = FastGraph.from_dict(0, body.get('txn'), raw=True)
            fg.verify()
        except:
            raise
            return 'invalid transaction', 400
        res = mongo.db.signed_transactions.find_one({'hash': body.get('hash')})
        if res:
            return 'no', 400
        try:
            rid = TU.generate_rid(config, body.get('bulletin_secret'))
            my_entry_for_relationship = GU().get_transaction_by_rid(
                rid,
                config.wif,
                rid=True,
                my=True,
                public_key=config.public_key)
            their_entry_for_relationship = GU().get_transaction_by_rid(
                rid,
                rid=True,
                raw=True,
                theirs=True,
                public_key=config.public_key)
            verified = verify_signature(
                base64.b64decode(body.get('bulletin_secret')),
                my_entry_for_relationship['relationship']
                ['their_username'].encode(),
                bytes.fromhex(their_entry_for_relationship['public_key']))
            if not verified:
                return 'no', 400
            verified = verify_signature(
                base64.b64decode(body.get('id')),
                body.get('hash').encode('utf-8'),
                bytes.fromhex(their_entry_for_relationship['public_key']))
            address = str(
                P2PKHBitcoinAddress.from_pubkey(
                    bytes.fromhex(their_entry_for_relationship['public_key'])))
            found = False
            async for x in self.config.BU.get_wallet_unspent_transactions(
                    address, [body.get('input')]):
                if body.get('input') == x['id']:
                    found = True

            if not found:
                for x in self.config.BU.get_wallet_unspent_fastgraph_transactions(
                        address):
                    if body.get('input') == x['id']:
                        found = True

            if found:
                signature = mongo.db.signed_transactions.find_one({
                    'input':
                    body.get('input'),
                    'txn.public_key':
                    body['txn']['public_key']
                })
                if signature:
                    already_spent = mongo.db.fastgraph_transactions.find_one({
                        'txn.inputs.id':
                        body['input'],
                        'txn.public_key':
                        body['txn']['public_key']
                    })
                    if already_spent:
                        self.set_status(400)
                        self.write('already spent!')
                        self.finish()
                        return True
                    else:
                        signature['txn']['signatures'] = [
                            signature['signature']
                        ]
                        fastgraph = FastGraph.from_dict(0, signature['txn'])
                        try:
                            fastgraph.verify()
                        except Exception as e:
                            raise
                            return 'did not verify', 400
                        result = mongo.db.fastgraph_transactions.find_one(
                            {'txn.hash': fastgraph.hash})
                        if result:
                            return 'duplicate transaction found', 400
                        spent_check = mongo.db.fastgraph_transactions.find_one(
                            {
                                'txn.inputs.id': {
                                    '$in': [x.id for x in fastgraph.inputs]
                                }
                            })
                        if spent_check:
                            return 'already spent input', 400
                        fastgraph.save()
            else:
                return 'no transactions with this input found', 400
            if verified:
                transaction_signature = TU.generate_signature_with_private_key(
                    config.private_key, body.get('hash'))
                signature = {
                    'signature': transaction_signature,
                    'hash': body.get('hash'),
                    'bulletin_secret': body.get('bulletin_secret'),
                    'input': body.get('input'),
                    'id': body.get('id'),
                    'txn': body.get('txn')
                }
                mongo.db.signed_transactions.insert(signature)
                if '_id' in signature:
                    del signature['_id']
                self.render_as_json(signature, indent=4)
            else:
                return 'no', 400
        except Exception as e:
            raise
            self.render_as_json({'status': 'error', 'msg': e})
Example #7
0
 def generate_transaction_signature(self):
     return TU.generate_signature(self.hash, self.private_key)
Example #8
0
    async def generate(cls,
                       bulletin_secret='',
                       username='',
                       value=0,
                       fee=0.0,
                       rid='',
                       requester_rid='',
                       requested_rid='',
                       public_key='',
                       dh_public_key='',
                       private_key='',
                       dh_private_key='',
                       to='',
                       inputs='',
                       outputs='',
                       coinbase=False,
                       chattext=None,
                       signin=None,
                       relationship='',
                       no_relationship=False,
                       exact_match=False):
        cls_inst = cls()
        cls_inst.config = get_config()
        cls_inst.mongo = cls_inst.config.mongo
        cls_inst.app_log = getLogger('tornado.application')
        cls_inst.bulletin_secret = bulletin_secret
        cls_inst.username = username
        cls_inst.rid = rid
        cls_inst.requester_rid = requester_rid
        cls_inst.requested_rid = requested_rid
        cls_inst.public_key = public_key
        cls_inst.dh_public_key = dh_public_key
        cls_inst.private_key = private_key
        cls_inst.value = value
        cls_inst.fee = float(fee)
        cls_inst.dh_private_key = dh_private_key
        cls_inst.to = to
        cls_inst.time = str(int(time.time()))
        cls_inst.outputs = []
        cls_inst.relationship = relationship
        cls_inst.no_relationship = no_relationship
        cls_inst.exact_match = exact_match
        for x in outputs:
            cls_inst.outputs.append(Output.from_dict(x))
        cls_inst.inputs = []
        for x in inputs:
            if 'signature' in x and 'public_key' in x and 'address' in x:
                cls_inst.inputs.append(ExternalInput.from_dict(x))
            else:
                cls_inst.inputs.append(Input.from_dict(x))
        cls_inst.coinbase = coinbase
        cls_inst.chattext = chattext
        cls_inst.signin = signin
        await cls_inst.do_money()

        inputs_concat = ''.join([
            x.id for x in sorted(cls_inst.inputs, key=lambda x: x.id.lower())
        ])
        outputs_concat = cls_inst.get_output_hashes()
        if bulletin_secret or rid:
            if not cls_inst.rid:
                cls_inst.rid = cls_inst.generate_rid()
            if cls_inst.chattext:
                cls_inst.relationship = json.dumps(
                    {"chatText": cls_inst.chattext})
                cls_inst.encrypted_relationship = cls_inst.config.cipher.encrypt(
                    cls_inst.relationship)
            elif cls_inst.signin:
                for shared_secret in cls_inst.config.GU.get_shared_secrets_by_rid(
                        cls_inst.rid):
                    cls_inst.relationship = SignIn(cls_inst.signin)
                    cls_inst.cipher = Crypt(shared_secret.hex(), shared=True)
                    cls_inst.encrypted_relationship = cls_inst.cipher.shared_encrypt(
                        cls_inst.relationship.to_json())
                    break
            elif cls_inst.relationship:
                cls_inst.encrypted_relationship = cls_inst.relationship
            elif cls_inst.no_relationship:
                cls_inst.encrypted_relationship = ''
            else:
                if not cls_inst.dh_public_key or not cls_inst.dh_private_key:
                    a = os.urandom(32).decode('latin1')
                    cls_inst.dh_public_key = scalarmult_base(a).encode(
                        'latin1').hex()
                    cls_inst.dh_private_key = a.encode().hex()
                cls_inst.relationship = cls_inst.generate_relationship()
                if not private_key:
                    raise Exception('missing private key')
                cls_inst.encrypted_relationship = cls_inst.config.cipher.encrypt(
                    cls_inst.relationship.to_json().encode())
        else:
            cls_inst.rid = ''
            cls_inst.encrypted_relationship = ''

        cls_inst.header = (cls_inst.public_key + cls_inst.time +
                           cls_inst.dh_public_key + cls_inst.rid +
                           cls_inst.encrypted_relationship +
                           "{0:.8f}".format(cls_inst.fee) +
                           cls_inst.requester_rid + cls_inst.requested_rid +
                           inputs_concat + outputs_concat)
        cls_inst.hash = hashlib.sha256(
            cls_inst.header.encode('utf-8')).digest().hex()
        if cls_inst.private_key:
            cls_inst.transaction_signature = TU.generate_signature_with_private_key(
                private_key, cls_inst.hash)
        else:
            cls_inst.transaction_signature = ''
        return cls(cls_inst.time,
                   cls_inst.rid,
                   cls_inst.transaction_signature,
                   cls_inst.encrypted_relationship,
                   cls_inst.public_key,
                   cls_inst.dh_public_key,
                   float(cls_inst.fee),
                   cls_inst.requester_rid,
                   cls_inst.requested_rid,
                   cls_inst.hash,
                   inputs=[x.to_dict() for x in cls_inst.inputs],
                   outputs=[x.to_dict() for x in cls_inst.outputs],
                   coinbase=cls_inst.coinbase)
Example #9
0
 def get_username_signature(self):
     from yadacoin.core.transactionutils import TU
     return TU.generate_deterministic_signature(self, self.username,
                                                self.private_key)