function crypt(private_key, public_key, nonce, message, checksum) {
    private_key = toPrivateObj(private_key)
    if (!private_key)
        throw new TypeError('private_key is required')

    public_key = toPublicObj(public_key)
    if (!public_key)
        throw new TypeError('public_key is required')

    nonce = toLongObj(nonce)
    if (!nonce)
        throw new TypeError('nonce is required')

    if (!Buffer.isBuffer(message)) {
        if (typeof message !== 'string')
            throw new TypeError('message should be buffer or string')
        message = new Buffer.from(message, 'binary')
    }
    if (checksum && typeof checksum !== 'number')
        throw new TypeError('checksum should be a number')

    const S = private_key.get_shared_secret(public_key);
    let ebuf = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN)
    ebuf.writeUint64(nonce)
    ebuf.append(S.toString('binary'), 'binary')
    ebuf = new Buffer.from(ebuf.copy(0, ebuf.offset).toBinary(), 'binary')
    const encryption_key = hash.sha512(ebuf)

    // D E B U G
    // console.log('crypt', {
    //     priv_to_pub: private_key.toPublicKey().toString(),
    //     pub: public_key.toString(),
    //     nonce: nonce.toString(),
    //     message: message.length,
    //     checksum,
    //     S: S.toString('hex'),
    //     encryption_key: encryption_key.toString('hex'),
    // })

    const iv = encryption_key.slice(32, 48)
    const key = encryption_key.slice(0, 32)

    // check is first 64 bit of sha256 hash treated as uint64_t truncated to 32 bits.
    let check = hash.sha256(encryption_key)
    check = check.slice(0, 4)
    const cbuf = ByteBuffer.fromBinary(check.toString('binary'), ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN)
    check = cbuf.readUint32()

    if (checksum) {
        if (check !== checksum)
            throw new Error('Invalid key')
        message = cryptoJsDecrypt(message, key, iv)
    } else {
        message = cryptoJsEncrypt(message, key, iv)
    }
    return {nonce, message, checksum: check}
}
@arg {Buffer} message - Encrypted or plain text message (see checksum)
    @arg {number} checksum - shared secret checksum (null to encrypt, non-null to decrypt)