[Bug 23369] Provide hooks for Typed Arrays (ArrayBuffer and friends)


--- Comment #37 from Ryan Sleevi <sleevi@google.com> ---
(In reply to Domenic Denicola from comment #34)
> I think you guys are talking past each other a bit. Allen is envisioning an
> API that allows you to "mark as immutable" array buffers, and suggesting
> that these methods should throw whenever given array buffers that aren't
> marked as such. 

No, I understood this.

This has two surprising consequences:
1) It prevents the use of ArrayBufferViews from working on slices of data with
such APIs - that is, you have to mark the underlying buffer as immutable, which
means if you want your use of ABV to have no non-local state, you're forcing
the application developer to copy.

This can be seen in the neutering behaviour discussions, which is essentially
the same thing.

2) It essentially forces copying into the application's responsibility, rather
than having it be part of the API. This doesn't seem to do anyone any favours.

Almost certainly, the logical consequence of such an API is you'd want to
'unmark' something as immutable. This approach (mutable then unmutable) is what
Web Audio tried to do with "temporarily neuter". If you do introduce a
markMutable, when what you've really done is introduce a reader/writer lock on
ArrayBuffers. Is that really a good API choice? I honestly don't know, but I
feel like probably not.

I'm probably biased, because I'm approaching this from the cryptographic
operations. Consider something like PBKDF2 or HKDF, which are algorithms that
compose on existing algorithms (eg: HMAC) in a somewhat iterative way to
'expand' key material into a suitable derived key.

HKDF is defined somewhat recursively
   T(0) = empty string (zero length)
   T(1) = HMAC-Hash(PRK, T(0) | info | 0x01)
   T(2) = HMAC-Hash(PRK, T(1) | info | 0x02)
   T(3) = HMAC-Hash(PRK, T(2) | info | 0x03)

The resulting key is concatenating T(1), T(2), ... T(N) until you have enough
data to fit the desired length.

If I were writing this in C/C++, I'd typically start by allocating T (aligned
to HMAC-Hash length), and an "intermediate" buffer.

Then I'd write a loop

for (i = 1; i < N; ++i) {
  if (i == 1) {
    // set up intermediate
    HMAC(PRK, intermediate, intermediateLength, &T[0]);
  } else {
    memcpy(&intermediate[0], &T[(i - 1) * hashLength], hashLength);
    intermediate[intermediate.length - 1] = i;
    HMAC(PRK, intermediate, intermediateLength, &T[i * hashLength]);

While likely bugged in many ways, the net effect is that my code has performed
two allocations - one for the resulting buffer, and one for the intermediate

If I were to implement this in ES, with WebCrypto, I'd likely do something
similar. I'd have a Uint8Array called T, which had my targetted results. I'd
have a Uint8Array, intermediate, that contains my intermediate data.

Now, WebCrypto doesn't do emplacement-writes, it always returns a fresh
ArrayBuffer, so I'd do a Promise to get T(1), then copy that into
T[0...hashLength]. Then I'd do a Promise to get T(2), and copy that into
[hashLength...hashLength*2], then a Promise for T(3), copy that into

As Web Crypto is currently specified, I can use "intermediate" as my scratch,
and keep mutating it (updating the count and copying the result from T(i-1)
in). Web Crypto will take responsibility for 'snapshotting' intermediate for
each state.

If we required .markImmutable(), then I, as the application author, would be
forced to create a new copy of the data each time, as part of my algorithm.

That 'smells' to me for two reasons:
1) I assume (perhaps incorrectly) that by keeping the copying on the UA side of
things, I'm allowing greater flexibility for memory management strategies
2) As an author, that's more boilerplate for me to write in order for things to
"Just Work"

You are receiving this mail because:
You are on the CC list for the bug.

Received on Wednesday, 18 June 2014 19:14:45 UTC