Open Jack-Edwards opened 1 year ago
I have some basic examples of using the libsodium wrappers with MemoryView, ArraySegment, and Span.
[JSImport("randomBytes_MemoryViewTest", "blazorSodium")]
public static partial void RandomBytes_Buf_MemoryView_Test(int size, [JSMarshalAs<JSType.MemoryView>] ArraySegment<byte> buffer);
export function randomBytes_MemoryViewTest(size, buffer) {
buffer.set(sodium.randombytes_buf(size));
}
and
[JSImport("cryptoShortHashMemoryView", "blazorSodium")]
public static partial void Crypto_ShortHash_MemoryView_Test([JSMarshalAs<JSType.MemoryView>] ArraySegment<byte> hashBuffer, [JSMarshalAs<JSType.MemoryView>] Span<byte> messageBuffer, [JSMarshalAs<JSType.MemoryView>] Span<byte> keyBuffer);
export function cryptoShortHashMemoryView(hashBuffer, messageBuffer, keyBuffer) {
hashBuffer.set(sodium.crypto_shorthash(messageBuffer.slice(), keyBuffer.slice()));
}
Overall, performance actually takes a huge hit when using MemoryView. In cases where I was passing byte[]
to a method which accepted ArraySegment<byte>
and Span<byte>
, the overhead to change the types on the fly is huge. It took 4x longer to process the same data.
The impact is less dramatic when you convert to ArraySegment<byte>
before calling a method and keep that ArraySegment alive for multiple calls into libsodium. But performance is still worse.
The only case where I could find an improvement in performance is when doing something drastic, such as hashing a buffer containing 100_000 or more bytes 10_000 or more times. Even then, the tests only completed 5% faster. Really not worth the trouble.
Thought to be fair I've only tested on my own development computer, which is relatively powerful with good memory speeds.
I still theorize there are significant performance gains to be had. Take this encryption example:
I can provide a MemoryView of ArraySegment
The problem is I can't figure out how to use the base or "unwrapped" libsodium.js methods. These methods take buffer addresses instead of array instances. But whenever I provide an IntPtr from C# to these methods, I get an "index out of bounds" error from the runtime. Is the runtime guarding against whatever libsodium is doing to the managed memory space? Am I not allocating enough space in the buffer? Is libsodium only looking within it's own memory space?
Libsodium.js offers some nice wrappers to make using the library a lot simpler. However, using these wrappers means we are often copying data to and from JavaScript on every call.
It's possible to use
MemoryView
in .NET 7 to give JavaScript access to managed memory. For example:C#
JS
The
buffer
created in managed memory can be directly accessed and manipulated by JavaScript without having to copy the data.One problem (among several) I'm facing is that the lower-level libsodium.js functions have extra, undocumented arguments. I opened a discussion topic for this on the main libsodium repo: https://github.com/jedisct1/libsodium/discussions/1222
Another problem I'm facing is libsodium.js rejects the raw
arraySegment
, as it is neither aUint8Array
nor astring
.slice()
should work to convert the data into an array that libsodium.js will accept, but that probably means I'll need to write a layer of JavaScript to interop between the C# calls and libsodium.js. Another option may be to create a fork of libsodium.js that tries toslice()
the data on it's own, but I really want to avoid this.