Как преобразовать Uint8Array в логический (бит) массив без использования строк? - PullRequest
0 голосов
/ 11 мая 2018

Я использую javascript, и я немного заржавел в своей арифметике.

В конечном счете, моя цель - преобразовать UInt8Array в 11-битные числа для использования со списком слов bip39 для преобразования ключа приватного ящика libsodium в мнемонику (я создаю небольшое приложение для чата p2p-ish).

Итак, мой мыслительный процесс выглядит так:

  1. Uint8Array возвращается из libsodium.crypto_box_keypair()
  2. Преобразование Uint8Array в 256-битный (логический) массив
  3. разделить 256-битный массив на 11-битные сегменты (2-мерный массив: ~ 24 x 11 бит)
  4. преобразовать каждый 11-битный массив в базовое число 10 (между 0 и 2047)

Шаги 2, 3и 4 можно объединить в один и тот же цикл.

Цель всего этого - эффективное преобразование массива Uint8Array в массив из 11-битных чисел (эффективно для компьютера - это не былоэффективно для меня).

У меня есть это на данный момент, но это не совсем правильно, и я чувствую себя немного хакерским (только из шагов 2 и 3, где я пытаюсь создать 11-битные сегменты)

// 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;
}

В настоящее время для 2048 я получаю 2 11-битных массива(ожидается), но содержимое / порядок неожиданны.

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

2048 - это 0b100_000_000_000

, где 12-я цифра справа - 1 (добавлены подчеркивания для облегчения чтения)

так может, похоже, у меня проблема с порядком байтов и, возможно, одна проблема?потому что истина в моем двойном массиве - 13-я позиция слева.

хотя, когда я тестирую с 4096 (13 бит (0b1_000_000_000_000))), я получаю это:

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

Здесьtrue - 12 слева и 22 справа.

Обновление

на @bergi, который спросил о порядке байтов.

enter image description here

Я не знаю, что такое порядок байтовэто.: - \

Обновление 2

Спасибо @harold за то, что пришли с ответом.У меня есть несколько тестов, которые я думаю подтверждает правильность

  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);
  });

первые 3 прохода, но последний нет.

при конвертации Uint8Array(28, 163), я получаю [796, 28]

Я не на 100%конечно, я правильно преобразовал 7331 в соответствующие байты, но я сделал: 7331 = 0b1_1100_1010_0011 split: [1_1100, 1010_0011] -> [28, 163].

Полагаю, для вывода это должно быть: [11, 100_1010_0011], что [3, 1187], что также не соответствует выводу.

Ответы [ 2 ]

0 голосов
/ 11 мая 2018

Я бы пошел на генераторы:

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;
}

Тогда используйте их как

const input = libsodium.crypto_box_keypair();
const result = Array.from(hendecadsFromBitsLE(bitsFromOctetsLE(input)))
0 голосов
/ 11 мая 2018

Я не так сильно разбираюсь в своей арифметике, поэтому предлагаю метод без временных логических массивов:

  • чтение байтов в буфер до тех пор, пока не будет не менее 11 бит
  • извлечение 11 битов из буфера
  • повтор

На самом деле забавная вещь случается в конце, так как 11 не делит 256, я предполагаю, что заполнение нулями в порядке.

Так что, может быть, что-то подобное в JavaScript (но я немного немного заржавел на моем JS)

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

    for (var i = 0; i < input.length; i++) {
        // prepend bits to buffer
        buffer |= input[i] << numbits;
        numbits += 8;
        // if there are enough bits, extract 11bit chunk
        if (numbits >= 11) {
            output.push(buffer & 0x7FF);
            // drop chunk from buffer
            buffer = buffer >> 11;
            numbits -= 11;
        }
    }
    // also output leftover bits
    if (numbits != 0)
        output.push(buffer);

    return output;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...