51
$\begingroup$

If I want to make package-code completely unreadable, in a way that the end-user can only call my functions, but has no way to re-engineer my definitions, how would I do that?

I know I can use Encode to make scrambled code which, quoting the doc, cannot be converted back by any Mathematica function. But even with an encoded package, the user could look at the definitions of my functions. So I should add some attributes: Protected, ReadProtected, Locked.

Would that be enough? Has someone experience with this?

Additional question: How do I distribute this? In the Workbench one has to process all Documentation files and can then create a .zip or a .tgz from its package, but there are unencoded files used. Do I have to encode the files by a script or is there already a solution?

$\endgroup$
5
  • $\begingroup$ There is the function DumpSave[] which allows you to write definitions into a file that is not quite human-readable... $\endgroup$ Feb 10, 2012 at 7:38
  • $\begingroup$ But DumpSaved files are possibly not readable on another system. It's the same point which @Szabolcs had in his "data storage question" $\endgroup$
    – halirutan
    Feb 10, 2012 at 7:41
  • $\begingroup$ You might want to look into what these guys did for their Mathematica packages; you can only download an encoded version, and the human readable versions can only be obtained through special circumstances. $\endgroup$ Feb 10, 2012 at 7:45
  • $\begingroup$ It seems you need a password even for downloading the encoded packages. $\endgroup$
    – halirutan
    Feb 10, 2012 at 7:54
  • $\begingroup$ Related: How safe is Encode? $\endgroup$
    – Szabolcs
    May 28, 2012 at 8:51

3 Answers 3

29
$\begingroup$

My suggestion is to use a combination of encryption, DumpSave (as noted in some answers / comments), and Locked / ReadProtected, which should give your code a reasonable level of security. You can't make things totally safe, in Mathematica or any other language. Using DumpSave however means that you should create a version of a package for each platform you want to support. But, if you really want to protect your code, this extra work does not seem that unreasonable.

$\endgroup$
3
  • $\begingroup$ For 11+ DumpSave is cross-platform, right? $\endgroup$
    – b3m2a1
    Dec 5, 2017 at 1:43
  • $\begingroup$ @b3m2a1It has been cross-platform since V10, if memory serves. With the caveats mentioned by Szabolcs. $\endgroup$ Dec 5, 2017 at 10:17
  • $\begingroup$ How would you use "encryption"? I took it to mean using Encodeon the mx file created by Dumpsave but I am having trouble with that here: mathematica.stackexchange.com/q/284528/60568 $\endgroup$ May 3, 2023 at 8:13
19
$\begingroup$

Mathematica-Users.org says:

The basic idea is to include commands at the end of your package which set the attributes of your "secret" functions to be ReadProtected, and then Locked. The ReadProtected means no one can see the function definitions, and the Locked means no one can undo the ReadProtected attribute.

It is probably not a good idea to also set the attribute Protected, because with Locked also engaged, your users will not be able to SetOptions on your functions.

The package file is still human readable and offers no protection from prying eyes. Saving the notebook as a package file in ".mx" format with the attributes set as indicated, offers protection from peepers, since the mx file is not human readable, but this option has some issues, mentioned above.

An alternative is to encode the package file with the Encode routine. This encrypts the package file, such that it is no longer human readable, but because it is an ASCII text file it is more portable. There is an exception to this portability - Linux encodes files differently from OS X and Windows.

The Needs or Get commands can read in the Encoded package file (possibly requiring a password, if you set one) and decrypt it, and once the package is in memory, the Locked and ReadProtect attributes now protect the secrets in your code. Here we give an example of this. We first show a trivial package that is written in a notebook, and saved as "demo.nb", for example. Since it's a tiny package it might contain only one cell, whose Cell Properties are set to "Initialization Cell". Here we assume the "secret function" we want to protect is the function "encrypt".

See the link for more.

I believe you must accept making OS-specific packages. This is what I recall from a MathGroup thread that I cannot currently find.

$\endgroup$
1
  • 1
    $\begingroup$ I think that the information about the OS dependency might not be correct anymore for version 8. If my memory isn't fooling me for earlier versions a package encoded on linux could be read everywhere but not the other way round. I think with 8 it should now work across all remaining platforms but can't find a reference nor test it right now. If one is after maximal security, distributing code in .mx format might be a better choice, as mentioned in Leonids answer. $\endgroup$ Feb 11, 2012 at 22:58
10
$\begingroup$

Something I once tried, but never really used, so no guarantees - but perhaps it is useful as a template:

LockContext[
  ctx_: ToString[
    Context[]]] := SetAttributes[Evaluate[ctx <> # & /@
     Names[ctx <> "*"]], {ReadProtected, Locked}]

This takes all defined symbols in ctx (default: current context) and applies some additional attributes to them. You could use this at the end of a package (respectively at the end of each - esp. the Private` context) to lock all relevant contexts and then save the encoded version (which is probably enough protection for the average honest user).

$\endgroup$
13
  • 2
    $\begingroup$ By assigning to Attributes you are deleting any attributes already set (like Flat or HoldAll), and thus potentially changing the semantics of the code. $\endgroup$
    – celtschk
    Feb 10, 2012 at 14:35
  • 2
    $\begingroup$ Done. Note that I've used the fact that SetAttributes can take a list as first argument to further simplify the code. $\endgroup$
    – celtschk
    Feb 11, 2012 at 10:16
  • 1
    $\begingroup$ I just noticed that you should be able to easily get around this by loading the module inside a block like this: Block[{Locked=ReadProtected},Get["yourpackage`"]]. $\endgroup$
    – celtschk
    Feb 14, 2012 at 18:19
  • 7
    $\begingroup$ Not anymore in Version 9, since now, finally, Locked is Locked ... $\endgroup$ Dec 30, 2012 at 16:47
  • 1
    $\begingroup$ @RolfMertig - Did you ever get to doing this? Any additional thoughts? $\endgroup$
    – Jagra
    Apr 25, 2014 at 12:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.