def buildTxApdu(dongle_path, data): """ Generate apdu from data. This apdu is to be sent into the ledger key. Argument: dongle_path -- value returned by parseBip32Path data -- bytes value returned by dposlib.core.crypto.getBytes Return bytes """ path_len = len(dongle_path) if len(data) > 255 - (path_len + 1): data1 = data[:255 - (path_len + 1)] data2 = data[255 - (path_len + 1):] p1 = util.unhexlify("e0040040") else: data1 = data data2 = util.unhexlify("") p1 = util.unhexlify("e0048040") return [ p1 + util.intasb(1 + path_len + len(data1)) + util.intasb(path_len // 4) + dongle_path + data1, util.unhexlify("e0048140") + util.intasb(len(data2)) + data2 if len(data2) else None ]
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: dict: public, private and WIF keys. """ if isinstance(secret, int): privateKey = "%064x" % secret seed = unhexlify(privateKey) elif isinstance(secret, str): privateKey = secret if HEX.match(secret) else \ secp256k1.hash_sha256(secret).decode() seed = unhexlify(privateKey) elif isinstance(secret, bytes): privateKey = secret.decode() if BHEX.match(secret) else \ secp256k1.hash_sha256(secret).decode() seed = unhexlify(privateKey) publicKey = secp256k1.PublicKey.from_seed(seed) return { "publicKey": publicKey.encode().decode(), "privateKey": privateKey, "wif": getWIF(seed) }
def buildSignatureApdu(data, dongle_path, what="tx", schnorr=True): apdu = [] path_len = len(dongle_path) payload = len(data) + len(dongle_path) + 1 if payload > payloadMax: raise CommException('Payload size:', payload, 'exceeds max length:', payloadMax) data = splitData(data, dongle_path) if len(data) == 1: first, body, last = data[0], [], None else: first, body, last = data[0], data[1:-1], data[-1] p2 = p2_schnorr_leg if schnorr else p2_ecdsa p1 = p1_single if last is None else p1_first op = getattr(sys.modules[__name__], "op_sign_" + what) apdu.append( unhexlify(cla + op + p1 + p2) + intasb(path_len + 1 + len(first)) + intasb(path_len // 4) + dongle_path + first) for b in body: apdu.append(unhexlify(cla + op + p1_more + p2) + intasb(len(b)) + b) if last is not None: apdu.append( unhexlify(cla + op + p1_last + p2) + intasb(len(last)) + last) return apdu
def serialize(tx): buf = BytesIO() # deal with vendorField if "vendorFieldHex" in tx: vendorField = unhexlify(tx["vendorFieldHex"]) else: vendorField = tx["vendorField"].encode("utf-8") # common part pack("<BBBBI", buf, (255, Transaction.VERSION, rest.cfg.pubKeyHash, tx["type"], tx["timestamp"])) pack_bytes(buf, unhexlify(tx["senderPublicKey"])) pack("<QB", buf, (tx["fee"], len(vendorField))) pack_bytes(buf, vendorField) # custom part pack_bytes(buf, serializePayload(tx)) #signatures part pack_bytes(buf, unhexlify(tx["signature"])) if "signSignature" in tx: pack_bytes(buf, unhexlify(tx["signSignature"])) elif "secondSignature" in tx: pack_bytes(buf, unhexlify(tx["secondSignature"])) result = buf.getvalue() buf.close() return result
def test_get_id_from_bytes(self): self.assertEqual( "0091128b8cb24758c8d1ed1dfe9c7ac3713691f54b96ce12ca3cbc675aa13d9a", dposlib.core.crypto.getIdFromBytes( bin_.unhexlify(TestArkCrypto.signed_tx0_hex)) ) and self.assertEqual( "d6f5208aaf8988b97e12260c554d04a149845f0160aa82d8c53eaa0836d3cf56", dposlib.core.crypto.getIdFromBytes( bin_.unhexlify(TestArkCrypto.signSigned_tx0_hex)))
def getAddress(publicKey): """ Computes ARK address from keyring. Argument: keys (ArkyDict) -- keyring returned by `getKeys` Return str """ ripemd160 = hashlib.new('ripemd160', unhexlify(publicKey)).digest()[:20] seed = unhexlify(cfg.marker) + ripemd160 return base58.b58encode_check(seed)
def getAddress(publicKey): """ Computes ARK address from keyring. Argument: publicKey (str) -- public key string Return str """ ripemd160 = hashlib.new('ripemd160', unhexlify(publicKey)).digest()[:20] seed = unhexlify(cfg.marker) + ripemd160 b58 = base58.b58encode_check(seed) return b58.decode('utf-8') if isinstance(b58, bytes) else b58
def serialize(tx, **options): """ Serialize transaction. Args: tx (dict or Transaction): transaction object. Returns: bytes: transaction serial representation. """ buf = BytesIO() vendorField = tx.get("vendorField", "").encode("utf-8")[:255] version = tx.get("version", 1) # common part pack("<BBB", buf, (0xff, version, cfg.pubkeyHash)) if version >= 2: pack("<IHQ", buf, ( tx.get("typeGroup", 1), tx["type"], tx["nonce"], )) else: pack("<BI", buf, ( tx["type"], tx["timestamp"], )) pack_bytes(buf, unhexlify(tx["senderPublicKey"])) pack("<QB", buf, (tx["fee"], len(vendorField))) pack_bytes(buf, vendorField) # custom part pack_bytes(buf, serde.serializePayload(tx)) # signatures part if not options.get("exclude_sig", False): pack_bytes(buf, unhexlify(tx.get("signature", ""))) if not options.get("exclude_second_sig", False): pack_bytes(buf, unhexlify(tx.get("signSignature", ""))) if "signatures" in tx and not options.get("exclude_multi_sig", False): if version == 1: pack("<B", buf, (0xff, )) pack_bytes(buf, b"".join([unhexlify(sig) for sig in tx["signatures"]])) # id part if "id" in tx: pack_bytes(buf, unhexlify(tx.get("id", ""))) result = buf.getvalue() buf.close() return result
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 getSignature(tx, private): return hexlify( crypto_sign( hashlib.sha256(getBytes(tx)).digest(), unhexlify(private) )[:crypto_sign_BYTES] )
def buildPukApdu(dongle_path): path_len = len(dongle_path) return \ unhexlify(cla + op_puk + p1_non_confirm + p2_no_chaincode) + \ intasb(path_len + 1) + \ intasb(path_len // 4) + \ dongle_path
def _1_9(tx, buf): asset = tx.get("asset", {}) claim = asset.get("claim", False) if not claim: raise Exception("no claim data found") pack_bytes(buf, unhexlify(claim["lockTransactionId"])) pack_bytes(buf, claim["unlockSecret"].encode("utf-8"))
def _2_6(tx, buf): asset = tx.get("asset", {}) data = asset.get("data", {}) registrationId = unhexlify(asset.get("registrationId", "")) try: ipfs = data.get("ipfsData", "") ipfs = \ str(ipfs).encode("utf-8") if not isinstance(ipfs, bytes) \ else ipfs except Exception as e: raise Exception("bad ipfs hash\n%r" % e) try: name = data.get("name", "") name = \ str(name).encode("utf-8") if not isinstance(name, bytes) \ else name except Exception as e: raise Exception("bad entity name\n%r" % e) pack( "<BBBB", buf, ( int(asset.get("type", 0)), int(asset.get("subType", 0)), int(asset.get("action", 0)), len(registrationId) ) ) pack_bytes(buf, registrationId) pack("<B", buf, (len(name), )) pack_bytes(buf, name) pack("<B", buf, (len(ipfs), )) pack_bytes(buf, ipfs)
def _1_1(tx, buf): asset = tx.get("asset", {}) if "signature" in asset: secondPublicKey = asset["signature"]["publicKey"] else: raise Exception("no secondSecret or secondPublicKey given") pack_bytes(buf, unhexlify(secondPublicKey))
def _9000_0(tx, buf): asset = tx["asset"].get("nftCollection", {}) name = asset["name"] if 5 <= len(name) <= 40: pack("<B", buf, (len(name), )) pack_bytes(buf, name.encode("utf-8")) else: raise Exception("bad namelength [5-80]: %s" % name) description = asset["description"] if 5 <= len(description) <= 80: pack("<B", buf, (len(description), )) pack_bytes(buf, description.encode("utf-8")) else: raise Exception("bad description length [5-80]: %s" % description) pack("<I", buf, (max(1, asset["maximumSupply"]), )) jsonSchema = compactJson(asset["jsonSchema"]) pack("<I", buf, (len(jsonSchema), )) pack_bytes(buf, jsonSchema.encode("utf-8")) allowedIssuers = asset.get("allowedIssuers", [])[:10] pack("<I", buf, (len(allowedIssuers), )) for allowedIssuer in allowedIssuers: pack_bytes(buf, unhexlify(allowedIssuer)) metadata = compactJson(asset.get("metadata", {})) pack("<I", buf, (len(metadata), )) pack_bytes(buf, metadata.encode("utf-8"))
def setVendorFieldHex(cls, value, encoding="utf-8"): value = value.decode(encoding) if isinstance(value, bytes) else value if (re.match(r"^[0-9a-fA-F]*$", value) is not None and len(value) % 2 == 0): cls._reset() cls._setitem("vendorField", unhexlify(value).decode(encoding)) else: raise ValueError("'%s' seems not be a valid hex string" % value)
def verifySignatureFromBytes(data, publicKey, signature): """ Verify signature. Args: data (bytes): data publicKey (str): public key as hex string signature (str): signature as hex string Returns: True if signature matches the public key """ pubkey = unhexlify(publicKey) msg = secp256k1.hash_sha256(data) sig = unhexlify(signature) if len(signature) == 128: return schnorr.bcrypto410_verify(msg, pubkey, sig) else: return ecdsa.verify(msg, pubkey, sig)
def getAddress(publicKey, marker=None): """ Compute ARK address from publicKey. Args: publicKey (str): public key marker (int): network marker (optional) Returns: the address """ if marker and isinstance(marker, int): marker = hex(marker)[2:] else: marker = None ripemd160 = hashlib.new('ripemd160', unhexlify(publicKey)).digest()[:20] seed = unhexlify(cfg.marker if not marker else marker) + ripemd160 b58 = base58.b58encode_check(seed) return b58.decode('utf-8') if isinstance(b58, bytes) else b58
def _1_3(tx, buf): asset = tx.get("asset", {}) delegatePublicKeys = asset.get("votes", False) if delegatePublicKeys: pack("<B", buf, (len(delegatePublicKeys), )) for delegatePublicKey in delegatePublicKeys: delegatePublicKey = delegatePublicKey.replace("+", "01") \ .replace("-", "00") pack_bytes(buf, unhexlify(delegatePublicKey)) else: raise Exception("no up/down vote given")
def verifySignature(value, publicKey, signature): """ Verify signature. Args: value (str): value as hex string publicKey (str): public key as hex string signature (str): signature as hex string Returns: True if signature matches the public key """ return verifySignatureFromBytes(unhexlify(value), publicKey, signature)
def verifySignatureFromBytes(data, publicKey, signature): """ Verify signature. Arguments: data (bytes) -- data in bytes publicKey (str) -- a public key as hex string signature (str) -- a signature as hex string Return bool """ if len(publicKey) == 66: publicKey = uncompressEcdsaPublicKey(publicKey) verifyingKey = VerifyingKey.from_string(unhexlify(publicKey), SECP256k1, hashlib.sha256) try: verifyingKey.verify(unhexlify(signature), data, hashlib.sha256, sigdecode_der) except (BadSignatureError, UnexpectedDER): return False return True
def verifySignature(value, publicKey, signature): """ Verify signature. Arguments: value (bytes) -- value as hex string in bytes publicKey (str) -- a public key as hex string signature (str) -- a signature as hex string Return bool """ return verifySignatureFromBytes(unhexlify(value), publicKey, signature)
def getWIF(seed): """ Computes WIF address from seed. Argument: seed (bytes) -- a sha256 sequence bytes Return str """ seed = unhexlify( cfg.wif) + seed[:32] + (b"\x01" if cfg.compressed else b"") return base58.b58encode_check(seed)
def _9000_1(tx, buf): asset = tx["asset"].get("nftToken", {}) pack_bytes(buf, unhexlify(asset["collectionId"])) attributes = compactJson(asset["attributes"]) pack("<I", buf, (len(attributes), )) pack_bytes(buf, attributes.encode("utf-8")) recipientId = asset.get("recipientId", "") pack("<B", buf, (len(recipientId), )) if recipientId: pack_bytes(buf, recipientId.encode("utf-8"))
def buildPkeyApdu(dongle_path): """ Generate apdu to get public key from ledger key. Argument: dongle_path -- value returned by parseBip32Path Return bytes """ path_len = len(dongle_path) return util.unhexlify("e0020040") + util.intasb(1 + path_len) + \ util.intasb(path_len//4) + dongle_path
def getWIF(seed): """ Compute WIF address from seed. Args: seed (bytes): a sha256 sequence bytes Returns: WIF address """ if hasattr(cfg, "wif"): seed = unhexlify(cfg.wif) + seed[:32] + b"\x01" # \x01 -> compressed b58 = base58.b58encode_check(seed) return str(b58.decode('utf-8') if isinstance(b58, bytes) else b58)
def getBytes(tx): buf = BytesIO() # write type and timestamp pack("<bi", buf, (tx["type"], tx["timestamp"])) # write senderPublicKey as bytes in buffer pack_bytes(buf, unhexlify(tx["senderPublicKey"])) # if there is a requesterPublicKey if "requesterPublicKey" in tx: pack_bytes(buf, unhexlify(tx["requesterPublicKey"])) # if there is a recipientId if "recipientId" in tx: pack(">Q", buf, (int(tx["recipientId"][:-len(cfg.marker)]),)) else: pack(">Q", buf, (0,)) # write amount pack("<Q", buf, (int(tx["amount"]),)) # if there is asset data if tx.get("asset", False): asset = tx["asset"] typ = tx["type"] if typ == 1 and "signature" in asset: pack_bytes(buf, unhexlify(asset["signature"]["publicKey"])) elif typ == 2 and "delegate" in asset: pack_bytes(buf, asset["delegate"]["username"].encode("utf-8")) elif typ == 3 and "votes" in asset: pack_bytes(buf, "".join(asset["votes"]).encode("utf-8")) else: pass # if there is a signature if tx.get("signature", False): pack_bytes(buf, unhexlify(tx["signature"])) # if there is a second signature if tx.get("signSignature", False): pack_bytes(buf, unhexlify(tx["signSignature"])) result = buf.getvalue() buf.close() return result
def _9000_2(tx, buf): asset = tx["asset"].get("nftTransfer", {}) nftIds = asset["nftIds"][0:10] pack("<B", buf, (len(nftIds), )) for nftId in nftIds: pack_bytes(buf, unhexlify(nftId)) recipientId = \ str(tx["recipientId"]) \ if not isinstance(tx["recipientId"], bytes) \ else tx["recipientId"] recipientId = base58.b58decode_check(recipientId) pack_bytes(buf, recipientId)
def _1_4(tx, buf): asset = tx.get("asset", {}) multiSignature = asset.get("multiSignature", False) if multiSignature: pack( "<BB", buf, ( multiSignature["min"], len(multiSignature["publicKeys"]) ) ) pack_bytes( buf, b"".join( [unhexlify(sig) for sig in multiSignature["publicKeys"]] ) )
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))