Пример #1
0
def getKeys(secret, seed=None):
    """
	Generate keyring containing public key, signing and checking keys as
	attribute.

	Keyword arguments:
	secret (str or bytes) -- a human pass phrase
	seed (byte) -- a sha256 sequence bytes (private key actualy)

	Return dict
	"""
    if secret and not isinstance(secret, bytes):
        secret = secret.encode('utf-8')
    seed = hashlib.sha256(secret).digest() if not seed else seed
    signingKey = SigningKey.from_secret_exponent(
        int(binascii.hexlify(seed), 16), SECP256k1, hashlib.sha256)
    publicKey = signingKey.get_verifying_key().to_string()
    return {
        "publicKey":
        hexlify(
            compressEcdsaPublicKey(publicKey) if cfg.compressed else publicKey
        ),
        "privateKey":
        hexlify(signingKey.to_string()),
        "wif":
        getWIF(seed)
    }
Пример #2
0
 def test_get_bytes_and_hexlify(self):
     self.assertEqual(
         TestArkCrypto.signed_tx0_hex,
         bin_.hexlify(
             dposlib.core.crypto.getBytes(TestArkCrypto.signed_tx0_dict)))
     self.assertEqual(
         TestArkCrypto.signSigned_tx0_hex,
         bin_.hexlify(
             dposlib.core.crypto.getBytes(
                 TestArkCrypto.signSigned_tx0_dict)))
Пример #3
0
    def multiSignWithKey(self, privateKey):
        """
        Add a signature in `signatures` field according to given index and
        privateKey.

        Args:
            privateKey (str): private key as hex string.
        """
        # remove id if any and set fee if needed
        self.pop("id", False)
        if "fee" not in self:
            setFees(self)
        # get public key from private key
        publicKey = dposlib.core.crypto.secp256k1.PublicKey.from_seed(
            unhexlify(privateKey))
        publicKey = hexlify(publicKey.encode())
        # create a multi-signature
        signature = dposlib.core.crypto.getSignatureFromBytes(
            serialize(self,
                      exclude_sig=True,
                      exclude_multi_sig=True,
                      exclude_second_sig=True), privateKey)
        # add multisignature in transaction
        try:
            self.appendMultiSignature(publicKey, signature)
        except Exception:
            raise ValueError("public key %s not allowed here" % publicKey)
Пример #4
0
def getSignatureFromBytes(data, privateKey):
    """
    Generate signature from data using private key.

    Args:
        data (bytes): bytes sequence
        privateKey (str): private key as hex string
    Returns:
        signature as hex string
    """
    secret0 = unhexlify(privateKey)
    msg = secp256k1.hash_sha256(data)
    if bytearray(data)[0] == 0xff:
        return hexlify(schnorr.bcrypto410_sign(msg, secret0))
    else:
        return hexlify(ecdsa.rfc6979_sign(msg, secret0, canonical=True))
Пример #5
0
 def test_transaction_sign(self):
     tx = dposlib.core.Transaction(TestArkCrypto.tx0_dict)
     tx.link(self.secret, self.secondSecret)
     tx.sign()
     if tx.get("version", 1) >= 2:
         return None
     self.assertEqual(tx["signature"],
                      TestArkCrypto.signed_tx0_dict["signature"])
     self.assertEqual(bin_.hexlify(dposlib.core.crypto.getBytes(tx)),
                      TestArkCrypto.signed_tx0_hex)
     tx.signSign()
     self.assertEqual(tx["signSignature"],
                      TestArkCrypto.signSigned_tx0_dict["signSignature"])
     self.assertEqual(bin_.hexlify(dposlib.core.crypto.getBytes(tx)),
                      TestArkCrypto.signSigned_tx0_hex)
     tx.unlink()
Пример #6
0
def getSignature(tx, private):
	return hexlify(
		crypto_sign(
			hashlib.sha256(getBytes(tx)).digest(),
			unhexlify(private)
		)[:crypto_sign_BYTES]
	)
Пример #7
0
def getIdFromBytes(data):
    """
	Generate data id.

	Arguments:
	data (bytes) -- data in bytes

	Return str
	"""
    return hexlify(hashlib.sha256(data).digest())
Пример #8
0
def getIdFromBytes(data):
    """
    Generate data id.

    Args:
        data (bytes): data as bytes sequence
    Returns:
        id as hex string
    """
    return hexlify(secp256k1.hash_sha256(data))
Пример #9
0
def getId(tx):
    """
	Generate transaction id.

	Arguments:
	tx (dict) -- a transaction description

	Return str
	"""
    return hexlify(hashlib.sha256(getBytes(tx)).digest())
Пример #10
0
def remoteSignWithSecret(network, ms_publicKey, txid, secret=None):
    return remoteSignWithKey(
        network, ms_publicKey, txid,
        hexlify(
            secp256k1.hash_sha256(
                secret if secret is not None else
                getpass.getpass("secret > ")
            )
        )
    )
Пример #11
0
 def setUpClass(self):
     prikey0 = secp256k1.hash_sha256("secret")
     self.publicKey = hexlify(
         secp256k1.PublicKey.from_seed(prikey0).encode())
     self.privateKey = hexlify(prikey0)
     self.msg_der = "00993c0b0003a02b9d5fdd1307c2ee4652ba54d492d1fd11a7d1b"\
                    "b3f3a44c4a05e79f19de9331eb8dd0e799b69714269474be623ce"\
                    "b3309020dff5756e69746573743a20747820776974682073696d7"\
                    "06c65207369676e61747572650000000000000000000000000000"\
                    "000000000000000000000000000000000000e1f50500000000c04"\
                    "b030000000000"
     self.msg_raw = "ff0217010000000000010000000000000003a02b9d5fdd1307c2e"\
                    "e4652ba54d492d1fd11a7d1bb3f3a44c4a05e79f19de933809698"\
                    "000000000000a08601000000000000000000171dfc69b54c7fe90"\
                    "1e91d5a9ab78388645e2427ea"
     self.der = "304402200ee92c78a690844eaabf6833ed4fe9c66db1476bcfaad1754"\
                "aec780116aa16b0022045e8fda963191c1df485ff18966df509679d8d"\
                "dd47e6fd51f2645309227fc5c9"
     self.raw = "4f01bd21828a633a3c821b9984fe642deab87237b99e62a543ca6948f"\
                "f1d6d32f2475ada1f933da0591c40603693614afa69fcb4caa2b4be01"\
                "8788de9f10c42a"
Пример #12
0
def htlcSecret(secret):
    """
    Compute an HTLC secret hex string from passphrase.

    Arguments:
        secret (str): passphrase
    Returns:
        transaction object
    """
    return hexlify(
        hashlib.sha256(secret if isinstance(secret, bytes) else secret.
                       encode("utf-8")).digest()[:16])
Пример #13
0
 def test_serialization(self):
     for tx in self.fixtures[:]:
         serialized = tx.pop("serialized", False)
         id_ = tx.pop("id", False)
         sig = tx.pop("signature", False)
         t = tx_.Transaction(tx)
         t.signature = sig
         computed = bin_.hexlify(
             dposlib.core.crypto.getBytes(
                 t, exclude_multi_sig=not t['type'] == 4))
         self.assertEqual(str(serialized), computed)
         self.assertEqual(id_, dposlib.core.crypto.getId(t))
Пример #14
0
def wifSignatureFromBytes(data, wif):
    """
    Generate signature from data using WIF key.

    Args:
        data (bytes): bytes sequence
        wif (str): wif key
    Returns:
        signature
    """
    seed = base58.b58decode_check(
        str(wif) if not isinstance(wif, bytes) else wif)[1:33]
    return getSignatureFromBytes(data, hexlify(seed))
Пример #15
0
def getKeys(secret):
    """
    Generate keyring containing secp256k1 keys-pair and wallet import format
    (WIF).

    Args:
        secret (str, bytes or int): anything that could issue a private key on
                                    secp256k1 curve
    Returns:
        public, private and WIF keys
    """
    if isinstance(secret, (str, bytes, unicode)):
        try:
            seed = unhexlify(secret)
        except Exception:
            seed = secp256k1.hash_sha256(secret)
    else:
        seed = secp256k1.bytes_from_int(secret)
    publicKey = secp256k1.PublicKey.from_seed(seed)
    return {
        "publicKey": hexlify(publicKey.encode()),
        "privateKey": hexlify(seed),
        "wif": getWIF(seed)
    }
Пример #16
0
def getSignature(tx, privateKey):
    """
	Generate transaction signature using private key.

	Arguments:
	tx (dict) -- a transaction description
	privateKey (str) -- a private key as hex string

	Return str
	"""
    signingKey = SigningKey.from_string(unhexlify(privateKey), SECP256k1,
                                        hashlib.sha256)
    return hexlify(
        signingKey.sign_deterministic(getBytes(tx),
                                      hashlib.sha256,
                                      sigencode=sigencode_der_canonize))
Пример #17
0
def getSignatureFromBytes(data, privateKey):
    """
	Generate data signature using private key.

	Arguments:
	data (bytes) -- data in bytes
	privateKey (str) -- a private key as hex string

	Return str
	"""
    signingKey = SigningKey.from_string(unhexlify(privateKey), SECP256k1,
                                        hashlib.sha256)
    return hexlify(
        signingKey.sign_deterministic(data,
                                      hashlib.sha256,
                                      sigencode=sigencode_der_canonize))
Пример #18
0
def sendApdu(apdus, debug=True):
    dongle = getDongle(debug)
    try:
        for apdu in apdus:
            data = bytes(dongle.exchange(apdu, timeout=30))
    except CommException as comm:
        if comm.sw == 0x6985:
            sys.stdout.write("Rejected by user\n")
        elif comm.sw in [0x6D00, 0x6F00, 0x6700]:
            sys.stdout.write("Make sure your Ledger is connected and unlocked "
                             "with the ARK app opened\n")
        else:
            sys.stdout.write("%r\n" % comm)
        data = b""
    finally:
        dongle.close()
    return hexlify(data)
Пример #19
0
def getMultiSignaturePublicKey(minimum, *publicKeys):
    """
    Compute ARK multi signature public key according to [ARK AIP #18](
        https://github.com/ArkEcosystem/AIPs/blob/master/AIPS/aip-18.md
    ).

    Args:
        minimum (int): minimum signature required
        publicKeys (list of str): public key list
    Returns:
        the multisignature public key
    """
    if 2 > minimum > len(publicKeys):
        raise ValueError("min signatures value error")
    P = secp256k1.PublicKey.from_secret("%02x" % minimum)
    for publicKey in publicKeys:
        P = P + secp256k1.PublicKey.decode(unhexlify(publicKey))
    return hexlify(P.encode())
Пример #20
0
def getPublicKey(dongle_path, debug=False):
    """
	Compute the public key associated to a derivation path.

	Argument:
	dongle_path -- value returned by parseBip32Path

	Keyword argument:
	debug -- flag to activate debug messages from ledger key [default: False]

	Return str (hex)
	"""

    apdu = buildPkeyApdu(dongle_path)
    dongle = getDongle(debug)
    data = bytes(dongle.exchange(apdu, timeout=30))
    dongle.close()
    len_pkey = util.basint(data[0])
    return util.hexlify(data[1:len_pkey + 1])
Пример #21
0
    def multiSignWithKey(self, privateKey):
        """
        Add a signature in `signatures` field according to given index and
        privateKey.

        Args:
            privateKey (str): private key as hex string
        """
        # get public key from private key
        publicKey = dposlib.core.crypto.secp256k1.PublicKey.from_seed(
            unhexlify(privateKey))
        publicKey = hexlify(publicKey.encode())

        # get public key index :
        # if type 4 find index in asset
        # else find it in _multisignature attribute
        if self["type"] == 4:
            index = self.asset["multiSignature"]["publicKeys"].index(publicKey)
        elif self._multisignature:
            if publicKey not in self._multisignature["publicKeys"]:
                raise ValueError("public key %s not allowed here" % publicKey)
            index = self._multisignature["publicKeys"].index(publicKey)
        else:
            raise Exception("multisignature not to be used here")

        # remove id if any and set fee
        self.pop("id", False)
        if "fee" not in self:
            self.setFee()

        # concatenate index and signature and fill it in signatures field
        # sorted(set([...])) returns sorted([...]) with unique values
        self["signatures"] = sorted(set(
            self.get("signatures", []) + [
                "%02x" % index + dposlib.core.crypto.getSignatureFromBytes(
                    serialize(self,
                              exclude_sig=True,
                              exclude_multi_sig=True,
                              exclude_second_sig=True), privateKey)
            ]),
                                    key=lambda s: s[:2])
Пример #22
0
def remoteSignWithKey(network, ms_publicKey, txid, privateKey):
    publicKey = hexlify(
        secp256k1.PublicKey.from_seed(unhexlify(privateKey)).encode()
    )

    wallet = getWallet(network, ms_publicKey).get("data", {})
    if txid in wallet:
        options = {} if wallet[txid]["type"] == 4 else {
            "exclude_sig": True,
            "exclude_multi_sig": True,
            "exclude_second_sig": True
        }
        return putSignature(
            network, ms_publicKey, txid, publicKey,
            crypto.getSignatureFromBytes(
                crypto.getBytes(wallet[txid], **options),
                privateKey
            )
        )
    else:
        raise Exception("%s transaction not found" % txid)
Пример #23
0
def getSignature(data, dongle_path, debug=False):
    """
	Get ledger Nano S signature of given transaction.

	Argument:
	data -- transaction as bytes data returned by dposlib.core.crypto.getBytes
	dongle_path -- value returned by parseBip32Path

	Keyword argument:
	debug -- flag to activate debug messages from ledger key [default: False]

	Return str (hex)
	"""

    apdu1, apdu2 = buildTxApdu(dongle_path, data)
    dongle = getDongle(debug)
    result = dongle.exchange(bytes(apdu1), timeout=30)
    if apdu2:
        apdu = util.unhexlify("e0048140") + util.intasb(len(apdu2)) + apdu2
        result = dongle.exchange(bytes(apdu), timeout=30)
    dongle.close()
    return util.hexlify(result)
Пример #24
0
def getSerial(network, ms_publicKey, txid):
    """
    ``GET /multisignature/{network}/{ms_publicKey}/{txid}/serial`` endpoint.
    Return specific pending transaction serial from a specific public key.
    """
    if network != getattr(rest.cfg, "network", False):
        rest.use(network)

    if flask.request.method != "GET":
        return json.dumps({
            "success": False,
            "API error": "GET request only allowed here"
        })

    tx = load(network, ms_publicKey, txid)
    if tx:
        return json.dumps({
            "success": True,
            "data": hexlify(crypto.getBytes(tx))
        }), 200
    else:
        return json.dumps({"success": False})
Пример #25
0
def htlcLock(amount, address, secret, expiration=24, vendorField=None):
    """
    Build an HTLC lock transaction. Emoji can be included in transaction
    vendorField using unicode formating.

    ```python
    >>> vendorField = u"message with sparkles \u2728"
    ```

    Args:
        amount (float): transaction amount in ark.
        address (str): valid recipient address.
        secret (str): lock passphrase.
        expiration (float): transaction validity in hour.
        vendorField (str): vendor field message.

    Returns:
        dposlib.ark.tx.Transaction: orphan transaction.
    """
    return Transaction(
        version=cfg.txversion,
        type=8,
        amount=amount*100000000,
        recipientId=address,
        vendorField=vendorField,
        asset={
            "lock": {
                "secretHash": hexlify(
                    hashlib.sha256(htlcSecret(secret).encode("utf-8")).digest()
                ),
                "expiration": {
                    "type": 1,
                    "value": int(slots.getTime() + expiration*60*60)
                }
            }
        }
    )
Пример #26
0
class Transaction(dict):
    """
    A python `dict` that implements all the necessities to manually generate
    valid transactions.
    """

    FMULT = None
    FEESL = None

    # custom properties definitions
    datetime = property(
        lambda cls: slots.getRealTime(cls["timestamp"]), None, None,
        "Transaction timestamp returned as python datetime object")
    fee = property(
        lambda cls: cls.get("fee", None),
        lambda cls, value: setFees(cls, value),
        None,
    )
    vendorField = property(
        lambda cls: cls.get("vendorField", None),
        lambda cls, value: setVendorField(cls, value),
        lambda cls: setVendorField(cls, ""),
    )
    vendorFieldHex = property(
        lambda cls: hexlify(cls.get("vendorField", "").encode("utf-8")),
        lambda cls, value: setVendorFieldHex(cls, value),
        lambda cls: setVendorField(cls, ""),
    )
    timestamp = property(lambda cls: cls.get("timestamp", None),
                         lambda cls, value: setTimestamp(cls, value), None,
                         "Transaction timestamp setter")
    recipientId = recipient = property(
        lambda cls: cls.get("recipientId", None),
        lambda cls, value: cls._setitem("recipientId", checkAddress(value)),
        lambda cls: cls.pop("recipientId", None),
        "Receiver address checker and setter")
    senderId = sender = property(
        lambda cls: cls.get("senderId", None),
        lambda cls, value: cls._setitem("senderId", checkAddress(value)),
        lambda cls: cls.pop("senderId", None),
        "Sender address checker and setter")
    senderPublicKey = property(
        lambda cls: cls.get("senderPublicKey", None),
        lambda cls, value: setSenderPublicKey(cls, value),
        lambda cls: deleteSenderPublicKey(cls),
        "Initialize transaction according to senderPublicKey value")
    secondSignature = signSignature = property(
        lambda cls: cls.get("signSignature", None),
        lambda cls, value: cls._setitem("signSignature", value),
        lambda cls: cls.pop("signSignature", None), "Second signature")
    #: If `True` then `amount` + `fee` = total arktoshi flow
    feeIncluded = property(
        lambda cls: "_amount" in cls.__dict__, lambda cls, value:
        (setFeeIncluded if bool(value) else unsetFeeIncluded)(cls), None,
        "if `True` then `amount` + `fee` = total arktoshi flow")

    @staticmethod
    def useDynamicFee(value="minFee"):
        """
        Activate and configure dynamic fees parameters. Value can be either an
        integer defining the fee multiplier constant or a string defining the
        fee level to use acccording to the 30-days-average. possible values are
        `avgFee` `minFee` (default) and `maxFee`.

        Args:
            value (str or int): constant or fee multiplier.
        """
        if hasattr(cfg, "doffsets"):
            if isinstance(value, (int, float)):
                Transaction.FMULT = int(value)
                Transaction.FEESL = None
            elif value in ["maxFee", "avgFee", "minFee"]:
                Transaction.FMULT = None
                Transaction.FEESL = value
            else:
                Transaction.FMULT = None
                Transaction.FEESL = None
        else:
            Transaction.FMULT = None
            Transaction.FEESL = None

    setDynamicFee = useDynamicFee
    useStaticFee = setStaticFee = lambda self: self.useDynamicFee(None)

    # private definitions
    def _setitem(self, item, value):
        try:
            cast = dposlib.core.TYPING[item]
        except KeyError:
            dict.__setattr__(self, item, value)
        else:
            if not isinstance(value, cast):
                value = cast(value)
            dict.__setitem__(self, item, value)

    def _reset(self):
        """remove data linked to validation process."""
        self.pop("signature", False)
        self.pop("signatures", False)
        self.pop("signSignature", False)
        self.pop("secondSignature", False)
        self.pop("id", False)

    def __init__(self, *args, **kwargs):
        self._ignore_bad_fields = kwargs.pop("ignore_bad_fields", False)
        self.FEESL = kwargs.pop("FEESL", Transaction.FEESL)
        self.FMULT = kwargs.pop("FMULT", Transaction.FMULT)
        # initialize a void dict
        dict.__init__(self)
        # if blockchain package loaded merge all elements else return void dict
        data = dict(*args, **kwargs)
        last_to_be_set = [(k, data.pop(k, None)) for k in [
            "fee", "nonce", "signatures", "signature", "signSignature",
            "secondSignature", "id"
        ]]
        # set default values
        dict.__setitem__(self, "version", data.pop("version", 2))
        dict.__setitem__(self, "network", getattr(cfg, "pubkeyHash", 30))
        dict.__setitem__(self, "typeGroup", data.pop("typeGroup", 1))
        dict.__setitem__(self, "amount", int(data.pop("amount", 0)))
        dict.__setitem__(self, "type", data.pop("type", 0))
        dict.__setitem__(self, "asset", data.pop("asset", {}))
        # initialize all non-void fields
        for key, value in [(k, v)
                           for k, v in list(data.items()) + last_to_be_set
                           if v is not None]:
            if key == "fee":
                value = int(value)
            self[key] = value

    def __setitem__(self, item, value):
        if item == "secret":
            self.link(value)
        elif item == "secondSecret":
            self.link(None, value)
        else:
            try:
                dict.__getattribute__(self, item)
            except AttributeError:
                self._setitem(item, value)
            else:
                object.__setattr__(self, item, value)

    __setattr__ = __setitem__

    def __getattr__(self, attr):
        try:
            return dict.__getitem__(self, attr)
        except KeyError:
            return dict.__getattribute__(self, attr)

    __getitem__ = __getattr__

    def __str__(self):
        return json.dumps(OrderedDict(sorted(self.items(),
                                             key=lambda e: e[0])),
                          indent=2)

    def __repr__(self):
        return "<Blockchain transaction type %(typeGroup)s:%(type)s>" % self

    def link(self, secret=None, secondSecret=None):
        """
        Save public and private keys derived from secrets. This is equivalent
        to wallet login. it limits number of secret keyboard entries.

        Args:
            secret (str): passphrase.
            secondSecret (str): second passphrase.
        """
        if hasattr(dposlib, "core"):
            if secret:
                keys = dposlib.core.crypto.getKeys(secret)
                self.senderPublicKey = keys["publicKey"]
                self._privateKey = keys["privateKey"]
            if secondSecret:
                keys = dposlib.core.crypto.getKeys(secondSecret)
                self._secondPrivateKey = keys["privateKey"]

    def unlink(self):
        try:
            deleteSenderPublicKey(self)
            del self._privateKey
            del self._secondPrivateKey
        except Exception:
            pass

    def touch(self):
        if hasattr(self, "_publicKey"):
            self.senderPublicKey = self._publicKey

    # root sign function called by others
    def sign(self):
        """
        Generate the `signature` field. Private key have to be set first.
        """
        self._reset()
        if hasattr(self, "_privateKey"):
            if "fee" not in self:
                setFees(self)
            if self.type == 4:
                missings = \
                    self.asset["multiSignature"]["min"] - \
                    len(self.get("signature", []))
                if missings:
                    raise Exception("owner signature missing (%d)" % missings)
            self["signature"] = dposlib.core.crypto.getSignature(
                self, self._privateKey)
        else:
            raise Exception("orphan transaction can not sign itsef")

    # root second sign function called by others
    def signSign(self):
        """
        Generate the `signSignature` field. Transaction have to be signed and
        second private key have to be set first.
        """
        if "signature" in self:  # or "signatures" in self ?
            self.pop("id", False)
            try:
                self["signSignature"] = dposlib.core.crypto.getSignature(
                    self,
                    self._secondPrivateKey,
                    exclude_second_sig=True,
                )
            except AttributeError:
                raise Exception("no second private Key available")
        else:
            raise Exception("transaction not signed")

    # sign functions using passphrases
    def signWithSecret(self, secret):
        """
        Generate the `signature` field using passphrase. The associated
        public and private keys are stored till `dposlib.ark.unlink` is called.

        Args:
            secret (`str`): passphrase.
        """
        self.link(secret)
        self.sign()

    def signSignWithSecondSecret(self, secondSecret):
        """
        Generate the `signSignature` field using second passphrase. The
        associated second public and private keys are stored till
        `dposlib.ark.unlink` is called.

        Args:
            secondSecret (`str`): second passphrase.
        """
        self.link(None, secondSecret)
        self.signSign()

    def multiSignWithSecret(self, secret):
        """
        Add a signature in `signatures` field.

        Args:
            index (int): signature index.
            secret (str): passphrase.
        """
        keys = dposlib.core.crypto.getKeys(secret)
        self.multiSignWithKey(keys["privateKey"])

    # sign function using crypto keys
    def signWithKeys(self, publicKey, privateKey):
        """
        Generate the `signature` field using public and private keys. They
        are stored till `dposlib.ark.unlink` is called.

        Args:
            publicKey (str): public key as hex string.
            privateKey (str): private key as hex string.
        """
        if self.get("senderPublicKey", None) != publicKey:
            self.senderPublicKey = publicKey
        self._privateKey = privateKey
        self.sign()

    def signSignWithKey(self, secondPrivateKey):
        """
        Generate the `signSignature` field using second private key. It is
        stored till `dposlib.ark.unlink` is called.

        Args:
            secondPrivateKey (`str`): second private key as hex string.
        """
        self._secondPrivateKey = secondPrivateKey
        self.signSign()

    def multiSignWithKey(self, privateKey):
        """
        Add a signature in `signatures` field according to given index and
        privateKey.

        Args:
            privateKey (str): private key as hex string.
        """
        # remove id if any and set fee if needed
        self.pop("id", False)
        if "fee" not in self:
            setFees(self)
        # get public key from private key
        publicKey = dposlib.core.crypto.secp256k1.PublicKey.from_seed(
            unhexlify(privateKey))
        publicKey = hexlify(publicKey.encode())
        # create a multi-signature
        signature = dposlib.core.crypto.getSignatureFromBytes(
            serialize(self,
                      exclude_sig=True,
                      exclude_multi_sig=True,
                      exclude_second_sig=True), privateKey)
        # add multisignature in transaction
        try:
            self.appendMultiSignature(publicKey, signature)
        except Exception:
            raise ValueError("public key %s not allowed here" % publicKey)

    def appendMultiSignature(self, publicKey, signature):
        # if type 4 find index in asset
        if self["type"] == 4:
            index = self.asset["multiSignature"]["publicKeys"].index(publicKey)
        # else find it in _multisignature attribute
        elif self._multisignature:
            index = self._multisignature["publicKeys"].index(publicKey)
        else:
            raise Exception("multisignature not to be used here")
        # concatenate index and signature and fill it in signatures field
        # sorted(set([...])) returns sorted([...]) with unique values
        self["signatures"] = sorted(
            set(self.get("signatures", []) + ["%02x" % index + signature]),
            key=lambda s: s[:2])

    def identify(self):
        """Generate the `id` field. Transaction have to be signed."""
        if "signature" in self or "signatures" in self:
            if len(self._multisignature):
                missings = \
                    self._multisignature["min"] - \
                    len(self.get("signatures", []))
                if missings:
                    raise Exception("owner signature missing (%d)" % missings)
            elif self._secondPublicKey:
                if "signSignature" not in self:
                    raise Exception("second signature is missing")
            self.pop("id", False)
            self["id"] = dposlib.core.crypto.getIdFromBytes(
                serialize(self, exclude_multi_sig=False))
        else:
            raise Exception("transaction not signed")

    def finalize(self,
                 secret=None,
                 secondSecret=None,
                 fee=None,
                 fee_included=False):
        """
        Finalize a transaction by setting `fee`, signatures and `id`.

        Args:
            secret (str): passphrase.
            secondSecret (str): second passphrase.
            fee (int): manually set fee value in `arktoshi`.
            fee_included (bool): see `dposlib.ark.tx.Transaction.feeIncluded`.
        """
        self.link(secret, secondSecret)
        # automatically set fees if needed
        if "fee" not in self or fee is not None:
            self.fee = fee
        self.feeIncluded = fee_included
        # sign with private keys
        # if transaction is not from a multisignature wallet
        if not self._multisignature:
            self.sign()
            if hasattr(self, "_secondPrivateKey"):
                self.signSign()
        # generate the id
        self.identify()
Пример #27
0
def getKeys(secret, seed=None):
	if not isinstance(secret, bytes): secret = secret.encode('utf-8')
	seed = hashlib.sha256(secret).digest() if not seed else seed
	publicKey, privateKey = list(hexlify(e) for e in crypto_sign_seed_keypair(seed))
	return {"publicKey": publicKey, "privateKey": privateKey}