You can’t use reinterpret because a BigInt is stored as a pointer and some lengths, but you can get at the raw bytes in a variety of ways, from low-level (exploit the raw pointer) to high-level. The best-documented way is to use the digits! function:
I am currently studying encryption algorithms. I was looking for solutions that would help me work at a high level (I was thinking about python). but I came across Julia. and now I’m trying to use it to do tests. and then write an optimized version in C
If you are reading an Int from a binary file or a stream io, you can do read(io, Int). You can even do this with an array bytes via read(io, IOBuffer(bytes)), or you can alternatively do reinterpret(Int, bytes)[1].
With BigInt, it depends on how the data is encoded in the array. If it’s an array bytes of base-256 digits (bytes) in little-endian order (least significant first) like what is returned from digits, you can treat it as a polynomial and use evalpoly(BigInt(256), bytes).
(There are also lower-level functions Base.GMP.MPZ.export! and Base.GMP.MPZ.import! that interface the low-level GMP export/import functions, but these are currently undocumented. It seems like it would be worthwhile to have a documented fast path, analogous to Python’s int.from_bytes function, though a need for this doesn’t seem to have come up much.)
What are you trying to accomplish? Converting BigInt values to and from arrays of base-256 digits doesn’t seem to be a very common operation. You can use parse and string to convert from/to strings in various bases, typically for serialization (storage) purposes, and you can also use serialize/deserialize.
You can do bitwise operations directly on BigInt values. Can you give an example of an operation that you would need to perform that requires conversion to/from a byte array?
Or is it more that you want to encrypt/decrypt an arbitrary byte stream by treating chunks of it as bignums?
In principle there is an even more efficient option: call the low-level mpz_combit function to flip a single bit of a bignum. Currently, Julia doesn’t export any high-level interface to this, but you can “easily” write one:
function combit!(n::BigInt, bit::Integer)
@ccall "libgmp".__gmpz_combit(n::Ref{BigInt}, bit::Culong)::Cvoid
return n
end
combit(n::BigInt, bit::Integer) = combit!(deepcopy(n), bit)
Then you can do combit(n, ndigits(n, base=256) * 8 - 1) to flip the highest bit of the most significant byte, or even call combit! to change n in-place.
You may very well have additional reasons for writing it in C but if we’re only discussing speed,chances are that you can get about the same performance in Julia as in C.
Note that this requires additional care when doing bignum operations, because when writing high-level operations each bignum operation like x + y heap-allocates a new bignum for the result. When writing low-level code you really want to work in-place as much as possible, reusing one of the operands for the result.
Of course, in Julia you do have access to the low-level in-place GMP functions if you really want, and there have been some attempts (e.g. Inplace.jl) to provide a higher-level interface to this. But it is important to point out that highly optimized Julia bignum code may look quite different from high-level bignum code.
(But it’s still easier to optimize the Julia code, where you only need to make localized incremental changes, than it is to rewrite from scratch in C/C++.)