Note that with the IRTools or the JLD2 solutions (or really anything that gives you a pure Julia function), they’re a @code_warntype away from seeing (a partially obfuscated version of) the source of the top-level function call:
# with IRTools solution from above
julia> @code_warntype g(nothing,2,1)
Body::Float64
1 ─ %1 = Core.apply_type(Base.Val, 2)::Core.Const(Val{2})
│ %2 = (%1)()::Core.Const(Val{2}())
│ %3 = Base.literal_pow(Main.:^, @_3, %2)::Int64
│ %4 = Main.sin(@_4)::Float64
│ %5 = (%3 + %4)::Float64
└── return %5
You can fix that by just wrapping the function in a closure, e.g.
julia> f = (x,y) -> (() -> x^2 + sin(y))();
At that point, you could just as well use the built-in Serialization to save the function:
julia> serialize("secret_function.jls", f);
julia> g = deserialize("secret_function.jls");
julia> @code_warntype g(1,2)
Body::Float64
1 ─ %1 = Serialization.__deserialized_types__.:(var"#14#16")::Core.Const(Serialization.__deserialized_types__.var"#14#16")
│ %2 = Core.typeof(x)::Core.Const(Int64)
│ %3 = Core.typeof(y)::Core.Const(Int64)
│ %4 = Core.apply_type(%1, %2, %3)::Core.Const(Serialization.__deserialized_types__.var"#14#16"{Int64, Int64})
│ (#14 = %new(%4, x, y))
│ %6 = #14::Serialization.__deserialized_types__.var"#14#16"{Int64, Int64}
│ %7 = (%6)()::Float64
└── return %7
julia> g(1,2)
1.9092974268256817
The contents of the file is pretty unreadable (though they may see that e.g. sin is used in someway, but doubt anyone can easily tell how):
7JL
43#13#15"XN�D""MLL�#13#�#NMainD#13aREPL[4]�SN�D3,FF9!#self#xy#14�LeF�63#14#16"}~,"}GF~GF", ,
LLL�#14#�#aNMainD#14aREPL[4]�SN�D3,!a#self#�LeF�V$N�D�%�}V$N�D�$N�DVal�V(�V$N�Dliteral_pow$NMainD^(�(�V$N�D�%�~V$NMainDsin(�V$NMainD�(�(�:(����NF�4LineInfoNodeN�DNMainD#14aREPL[4]����NFNN ��������LLLLN�)V$N�Dtypeof%�V$N�Dtypeof%�V$N�D�(�(�(�Y%��(�%�%�%�V(�:(����NF�4,eNMainD#13aREPL[4]���}~#14�NFNN ��������LLLLN�)
Although even still, the function is technically reconstructable in Julia if they @code_warntype into the deserialized closure, etc… Only way to make this Julia-proof is probably provide a dynamic library for a C compiled function.