nectar.memo module

class nectar.memo.Memo(from_account: str | Account | PrivateKey | None = None, to_account: str | Account | PublicKey | None = None, blockchain_instance: Any | None = None, **kwargs: Any)

Bases: object

Deals with Memos that are attached to a transfer

Parameters:
  • from_account (Account) – Account that has sent the memo

  • to_account (Account) – Account that has received the memo

  • blockchain_instance (Hive) – Hive instance

A memo is encrypted with a shared secret derived from a private key of the sender and a public key of the receiver. Due to the underlying mathematics, the same shared secret can be derived by the private key of the receiver and the public key of the sender. The encrypted message is perturbed by a nonce that is part of the transmitted message.

from nectar.memo import Memo
m = Memo("thecrazygm", "hive-nectar")
m.unlock_wallet("secret")
enc = (m.encrypt("test"))
print(enc)
>> {'message': '#DTpKcbxWqsETCRfjYGk9feERFa5nVBF8FaHfWPwUjyHBTgNhXGh4mN5TTG41nLhUcHtXfu7Hy3AwLrtWvo1ERUyAZaJjaEZNhHyoeDnrHdWChrzbccbANQmazgwjyxzEL', 'from': 'STM6MQBLaX9Q15CK3prXoWK4C6EqtsL7C4rqq1h6BQjxvfk9tuT3N', 'to': 'STM6sRudsxWpTZWxnpRkCDVD51RteiJnvJYCt5LiZAbVLfM1hJCQC'}
print(m.decrypt(enc))
>> foobar

To decrypt a memo, simply use

from nectar.memo import Memo
m = Memo()
m.unlock_wallet("secret")
print(m.decrypt(op_data["memo"]))

if op_data being the payload of a transfer operation.

Memo Keys

In Hive, memos are AES-256 encrypted with a shared secret between sender and receiver. It is derived from the memo private key of the sender and the memo public key of the receiver.

In order for the receiver to decode the memo, the shared secret has to be derived from the receiver’s private key and the senders public key.

The memo public key is part of the account and can be retrieved with the get_account call:

get_account <accountname>
{
  [...]
  "options": {
    "memo_key": "GPH5TPTziKkLexhVKsQKtSpo4bAv5RnB8oXcG4sMHEwCcTf3r7dqE",
    [...]
  },
  [...]
}

while the memo private key can be dumped with dump_private_keys

Memo Message

The take the following form:

{
  "from": "GPH5mgup8evDqMnT86L7scVebRYDC2fwAWmygPEUL43LjstQegYCC",
  "to": "GPH5Ar4j53kFWuEZQ9XhxbAja4YXMPJ2EnUg5QcrdeMFYUNMMNJbe",
  "nonce": "13043867485137706821",
  "message": "d55524c37320920844ca83bb20c8d008"
}

The fields from and to contain the memo public key of sender and receiver. The nonce is a random integer that is used for the seed of the AES encryption of the message.

Encrypting a memo

The high level memo class makes use of the nectar wallet to obtain keys for the corresponding accounts.

from nectar.memo import Memo
from nectar.account import Account

memoObj = Memo(
    from_account=Account(from_account),
    to_account=Account(to_account)
)
encrypted_memo = memoObj.encrypt(memo)

Decoding of a received memo

from getpass import getpass
from nectar.block import Block
from nectar.memo import Memo

# Obtain a transfer from the blockchain
block = Block(23755086)                   # block
transaction = block["transactions"][3]    # transactions
op = transaction["operations"][0]         # operation
op_id = op[0]                             # operation type
op_data = op[1]                           # operation payload

# Instantiate Memo for decoding
memo = Memo()

# Unlock wallet
memo.unlock_wallet(getpass())

# Decode memo
# Raises exception if required keys not available in the wallet
print(memo.decrypt(op_data["transfer"]))
decrypt(memo: str | Dict[str, Any]) str | None

Decrypt a memo message produced for a transfer.

Accepts either a raw memo string or a transfer-style dict with keys “from”, “to”, and “memo” or “message”. If provided, the memo dict may also contain a “nonce”. The function will locate an appropriate private memo key from the local wallet (or use a provided PrivateKey), derive the shared secret with the counterparty public key, and return the decrypted plaintext.

Parameters:
memo (str or dict): Encrypted memo as a string, or a dict in transfer form:

{“from”: <account|key>, “to”: <account|key>, “memo”/”message”: <str>, “nonce”?: <int|str>}. - “from”/”to” entries may be account names, account dicts, PublicKey/PrivateKey objects, or omitted.

Returns:

str: Decrypted memo plaintext, or None if memo is falsy.

Raises:

MissingKeyError: If no installed private memo key can be found for decrypting the message.

decrypt_binary(infile: str, outfile: str, buffer_size: int = 2048) Dict[str, Any]

Decrypt a binary file

Parameters:
  • infile (str) – encrypted binary file

  • outfile (str) – output file name

  • buffer_size (int) – read buffer size

Returns:

encrypted memo information

Return type:

dict

encrypt(memo: str, bts_encrypt: bool = False, return_enc_memo_only: bool = False, nonce: str | None = None) str | Dict[str, Any] | None

Encrypt a memo

Parameters:
  • memo (str) – clear text memo message

  • return_enc_memo_only (bool) – When True, only the encoded memo is returned

  • nonce (str) – when not set, a random string is generated and used

Returns:

encrypted memo

Return type:

dict

encrypt_binary(infile, outfile, buffer_size=2048, nonce=None)

Encrypt a binary file

Parameters:
  • infile (str) – input file name

  • outfile (str) – output file name

  • buffer_size (int) – write buffer size

  • nonce (str) – when not set, a random string is generated and used

extract_decrypt_memo_data(memo: str) Tuple[Any, Any, Any]

Returns information about an encrypted memo

unlock_wallet(*args: Any, **kwargs: Any) None

Unlock the library internal wallet