Is it possible to transform a Uint8Array into a boolean array without relying on strings?

My JavaScript skills are a bit rusty, especially when it comes to bit arithmetic.

The task at hand is converting a UInt8Array into 11-bit numbers. I need these numbers for a bip39 wordlist so that I can convert a libsodium private box key into a mnemonic. This is all part of a small peer-to-peer chat app project I'm working on.

Here's my plan:

  1. A Uint8Array is returned from libsodium.crypto_box_keypair()
  2. Convert the Uint8Array into a 256-bit (boolean) array
  3. Split the 256-bit array into 11-bit buckets (a 2D array: about 24 x 11 bits)
  4. Convert each 11-bit array into a base 10 number (ranging from 0 to 2047)

I believe steps 2, 3, and 4 can be combined within the same loop.

All this is to efficiently transform a UInt8Array into an array of 11-bit numbers; efficient for the computer, although it has been quite challenging for me personally.

Currently, I have this code snippet which attempts to create the 11-bit buckets:

// inspired from: https://github.com/pvorb/node-md5/issues/25
export function toUint11Array(input: Uint8Array): boolean[][] {
  let result: boolean[][] = [];
  let currentChunk: boolean[] = [];

  input.forEach(byte => {
    for (var j = 7; j >= 0; j--) {
      var b = ((byte >> j) & 0x1) > 0;

      if (currentChunk.length === 11) {
        result.push(currentChunk);
        currentChunk = [];
      }

      currentChunk.push(b);
    }
  });

  return result;
}

When testing with 2048, I get two 11-bit arrays as expected, but the content and order are not what I anticipated.

  [
    false, false, false, false,
    false, false, false, false,
    false, false, false
  ],
  [ false, true, false, false,
    false, false, false, false, 
    false, false, false
  ]

For 2048, where the 12th digit from the right should be '1', things seem off in terms of endianness and a possible off-by-one issue. Similar confusion arises when testing with 4096.

An update was made regarding the endianness concern, thanks to the community's support.

Update 2

Kudos to @harold who aided in solving the problem. Initial tests appear successful:

  const numbers = {
    ['32']: new Uint8Array([32]),
    ['64']: new Uint8Array([64]),
    ['2048']: new Uint8Array([8, 0]),
    ['4096']: new Uint8Array([16, 0]),
    ['7331']: new Uint8Array([28, 163])
  }

  test ('toUint11Array | converts | 32 (8 bits)', function(assert) {
    const result = toUint11Array(numbers['32']);
    const expected = [32];

    assert.deepEqual(result, expected);
  });

  test ('toUint11Array | converts | 2048 (12 bits)', function(assert) {
    const result = toUint11Array(numbers['2048']);
    const expected = [8, 0];

    assert.deepEqual(result, expected);
  });

  test ('toUint11Array | converts | 4096 (13 bits)', function(assert) {
    const result = toUint11Array(numbers['4096']);
    const expected = [16, 0];

    assert.deepEqual(result, expected);
  });



 test ('toUint11Array | converts | 7331 (13 bits)', function(assert) {
    const result = toUint11Array(numbers['7331']);
    const expected = [3, 1187];

    assert.deepEqual(result, expected);
  });

While the first three tests pass successfully, the last one does not generate the expected output when converting a Uint8Array(28, 163). Further refinement is needed to match the desired outcome.

Answer №1

My knowledge of bitwise arithmetic isn't as outdated, so here's a method that doesn't involve temporary boolean arrays:

  • Read bytes into a buffer until there are at least 11 bits
  • Extract 11 bits from the buffer
  • Repeat the process

It's worth noting that when 11 does not evenly divide 256, I assume padding with zeroes is acceptable.

Here's an approximation in JavaScript (although my JS skills may be a bit rusty)

function toUint11Array(input) {
    var buffer = 0, numbits = 0;
    var output = [];

    for (var i = 0; i < input.length; i++) {
        // Prepend bits to the buffer
        buffer |= input[i] << numbits;
        numbits += 8;

        // If there are enough bits, extract 11-bit chunk
        if (numbits >= 11) {
            output.push(buffer & 0x7FF);
            // Drop chunk from buffer
            buffer = buffer >> 11;
            numbits -= 11;
        }
    }

    // Output any leftover bits
    if (numbits != 0)
        output.push(buffer);

    return output;
}

Answer №2

The best choice would be to utilize generators:

function* bitsFromOctetsLE(octets) {
    for (let byte of octets) {
        for (let i=0; i<8; i++) {
            yield (byte & 1);
            byte >>= 1;
        }
    }
}
function* hendecadsFromBitsLE(bits) {
    let i=0;
    let val=0;
    for (const bit of bits) {
        if (i==11) {
            yield val;
            i = val = 0;
        }
        val |= bit << (i++);
    }
    if (i > 0) yield val;
}

You can then apply them in your code like this

const input = libsodium.crypto_box_keypair();
const result = Array.from(hendecadsFromBitsLE(bitsFromOctetsLE(input)))

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is it possible to attach a Vue component to more than one div element simultaneously?

import Selector from '@components/contactSelector' let vueInstance = new Vue({ components: { Selector }, data () { return { url: url, isFilter: false, type: 'external', selectedList: [] } }, rende ...

What is the rationale behind TypeScript permitting undefined methods?

Currently, I am working on a presentation for my development team about TypeScript. I want to demonstrate the importance of type checking through examples, but I'm stumped as to why this particular piece of code is not throwing a compile-time error wh ...

Error message: Three.js - Uncaught TypeError: THREE.OrbitControls is not defined as a constructor

I've been struggling to incorporate Orbit Controls into my scene but have hit a roadblock. Every time I try to add the code below, I keep encountering the error message Uncaught TypeError: THREE.OrbitControls is not a constructor. Despite attempting v ...

What could be causing the styled-component's flex value to not update?

I have a sidebar and main content on my website layout. The main content occupies most of the screen space, while the sidebar should only take up a small portion. Both elements are within a flexbox container, with the sidebar and main content as child divs ...

Custom typings for Next-Auth profile

I'm experiencing an issue with TypeScript and Next Auth type definitions. I followed the documentation guidelines to add my custom types to the NextAuth modules, specifically for the Profile interface in the next-auth.d.ts file. It successfully adds t ...

Tips on converting a comma "," to a forward slash "/" in an array with JavaScript

Is there a way in JavaScript to convert a string array with values separated by commas into a single string with values separated by slashes? For instance, can an array[] = { value1, a1/a2/a3} be transformed into array[] = {value1/a1/a2/a3} For example, ...

Guide on using Ajax to transmit data to Struts2 action class

In my Struts2 web application, I have the following files: member.jsp: <script type="text/javascript"> String str1 = "aaa"; String str2 = "bbb"; xmlhttp.open("GET", "http://localhost:8080/project/editprofile.action", true); xml ...

D3 Chart: What is the best way to insert images into a node?

Within the jsFiddle demo provided in this query, there is code displayed. I am curious about how I can assign images to each node. var graph = { "nodes":[ {"name":"1","rating":90,"id":2951}, ] } You can access my jsFiddle Demo through this ...

Easily conceal and reveal elements using Svelte in a straightforward manner

I'm looking for a straightforward method to hide and show an element using a button in Svelte. Can someone guide me on how to achieve this? Additionally, I'm curious if it's easier to accomplish this task with vanilla JavaScript. ...

The Storybook compilation consistently encounters errors

Check out my repository here: https://github.com/zapify-ui/zapify I'm facing an issue with building Storybook using the command: npm run build-storybook How can I identify the specific error or debug it effectively? The error thrown is: (node:46619) ...

What is the best way to implement an automatic logout feature in PHP?

I develop websites with login/logout functionality. Whenever a link or button is clicked on the website, I use an ajax function to verify the user's login status and automatically log them out if their session has expired. The logout function also up ...

jQuery.ajax Failure Response

When using MVC on the server side and calling a function with jQuery.Ajax that returns JSON, an exception is being thrown. How can I invoke the error handling function of Ajax by sending something back in the return JSON function? MVC Function public Jso ...

Forgetting your password with React JS

On my login page, there is a button labeled "Forget my password". When I click on this button, I want to be taken directly to the correct page for resetting my password. Currently, when I click on "forget my password", it displays beneath the login sectio ...

Creating a basic C++ program using Java concepts (Abstract class)

Java Programming Example (Successful) Define an abstract class Personnell with Manager and Worker as its subclasses. The class contains the abstract function getAnnualIncome(). Personnell employee[] = { new Manager("Thomas", "Nasa", 1337, 250000), ...

Using Asynchronous JavaScript and XML (AJAX) to make calls to a web service

My program is showing an internal server error var parameters = "<?xml version='1.0' encoding='utf-8'?>" + "<soap:envelope xmlns:xsi='ttp://www.w3.org/2001/xmlschema-instance' xmlns:xsd='http://www.w3. ...

Build a React application that dynamically renders components depending on the option selected in a dropdown

In my React application, there is a parent component that contains two child components (TrendsComponent and BaselineComponent) which load successfully. Additionally, the parent component includes a dropdown component. My goal is to have a default compone ...

Add MySQL JSON data to an array

Having an issue with a MySQL query in Node.js. After executing the query and receiving a JSON result, I'm trying to store the query result in an array variable. However, I'm having trouble accessing the elements of the array as it always returns ...

Assistance with AJAX Reload Interval (Polling) Functionality

My project involves extracting small portions of text from multiple files (often just single words) and then applying a stylized script to them. Currently, everything is functioning correctly in terms of loading and displaying the text. However, since the ...

Output repeated JSON Array in console using Node.js

Looking to identify duplicates within a JSON array based on the URL. var temp = [ { "name":"Allen", "site":"www.google.com/allen" }, { "name":"Chris", "site":&q ...

Establishing the correct data type to be returned from a fetch function in order to align with a specific custom type

My app has two interfaces defined: export interface Job { job_title: string, employer: string, responsibilities: string[] achievements: string[], start_date: string, end_date: string } export interface CreatedJob extends Job { ...