From c093445978a5ff9826726cb0178ab985f63c2594 Mon Sep 17 00:00:00 2001 From: Peter Date: Wed, 3 May 2023 13:44:15 -0600 Subject: [PATCH] start js bitstring library --- libs/vdk/src/bin.ts | 158 +++++++++++++++++++++++++++++++++++++++++++- libs/vdk/src/sp.ts | 23 +++++++ 2 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 libs/vdk/src/sp.ts diff --git a/libs/vdk/src/bin.ts b/libs/vdk/src/bin.ts index 1e8a382..58548b1 100644 --- a/libs/vdk/src/bin.ts +++ b/libs/vdk/src/bin.ts @@ -1,15 +1,71 @@ /** - * Binary utilities + * Miscellaneous binary utility functions * * @module */ export { bytes_to_bigint, - bigint_to_bytes + bigint_to_bytes, + concat, + strong_rand_bytes }; + +/** + * Concatenate two arrays + */ +function +concat + (arr1 : Uint8Array, + arr2 : Uint8Array) + : Uint8Array +{ + let len1 : number = arr1.length; + let len2 : number = arr2.length; + let arr1_idx0_offset : number = 0; + let arr2_idx0_offset : number = len1; + let result_len : number = len1 + len2; + let result : Uint8Array = new Uint8Array(result_len); + // copy first array into result + for (let arr1_idx0 = 0; + arr1_idx0 < len1; + arr1_idx0++) + { + // no offset here + let result_idx0 : number = arr1_idx0 + arr1_idx0_offset; + result[result_idx0] = arr1[arr1_idx0]; + } + // copy second array into result + for (let arr2_idx0 = 0; + arr2_idx0 < len2; + arr2_idx0++) + { + // offset by the length of the first array + let result_idx0 : number = arr2_idx0 + arr2_idx0_offset; + result[result_idx0] = arr2[arr2_idx0]; + } + return result; +} + + + +/** + * Cryptographically random bytes + */ +function +strong_rand_bytes + (how_many : number) + : Uint8Array +{ + let arr = new Uint8Array(how_many); + Crypto.getRandomValues(arr); + return arr; +} + + + /** * Convert a byte array to a bigint * @@ -58,3 +114,101 @@ bigint_to_bytes arr_reverse.reverse(); return new Uint8Array(arr_reverse); } + + + +/** + * Oh no, bitstrings in a language that only has bytestrings + * + * By convention these are `Uint8Array`s with byte length `ceil(bit_length / + * 8)`, and all trailing bits are zero. + */ +type bits = + {bit_length : number, + bytes : Uint8Array}; + + + +/** + * Get a bitstring of a given length where every value is 0. + */ +function +zeros + (bit_length : number) + : bits +{ + let byte_length : number = Math.ceil(bit_length / 8); + let result : Uint8Array = new Uint8Array(byte_length); + for (let i0 = 0; + i0 < byte_length; + i0++) + { + result[i0] = 0; + } + return {bit_length : bit_length, + bytes : result}; +} + + + +/** + * Get a bitstring of a given length where every value is 1. + */ +function +ones + (bit_length : number) + : bits +{ + let byte_length : number = Math.ceil(bit_length / 8); + let result : Uint8Array = new Uint8Array(byte_length); + + // fill everything except the last byte with 255s + for (let i0 = 0; + i0 < (byte_length - 1); + i0++) + { + result[i0] = 255; + } + + // alright so the last byte + // ok so the number of leading 0s is + // 8 - (bit_length % 8) + let num_trailing_zero_bits : number = 8 - (bit_length % 8); + // the trailing byte is 255 << that + // e.g. 3 trailing 0s + // 1111_1111 -> 1111_1000 + let last_byte : number = 255 << num_trailing_zero_bits; + let last_byte_idx0 : number = byte_length - 1; + result[last_byte_idx0] = last_byte; + + return {bit_length : bit_length, + bytes : result}; +} + + + +/** + * Get the bit at a given 0-index + */ +function +bit_i0th + (bit_idx0 : number, + bits : bits) + : number +{ + // first task is figuring out what byte we're at + // for instance if we want bit 27 + // 3*8 = 24 =< 27 < 4*8 + // so it's Math.floor(bit_idx0 / 8) + let byte_idx0 : number = Math.floor(bit_idx0 / 8); + // let's fetch the byte and work with that + let the_byte : number = bits.bytes[byte_idx0]; + + // ok so let's go with 27 again + // 27 = 3 mod 8 + // so we bitshift right by (8 - 3) + // and then take the remainder dividing by 2 + // --B-_---- -> ----_---B -> 0000_000B + let bsr : number = 8 - (bit_idx0 % 8); + return (the_byte >> bsr) % 2; +} diff --git a/libs/vdk/src/sp.ts b/libs/vdk/src/sp.ts new file mode 100644 index 0000000..8448945 --- /dev/null +++ b/libs/vdk/src/sp.ts @@ -0,0 +1,23 @@ +/** + * Vanillae Seed Phrase Library + * + * Refs: + * 1. BIP 39: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki + * + * @module + */ + + +/** + * Get a given number of seed bits. + * + * `how_many` must be a multiple of 33. + * + * Ref: https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki#generating-the-mnemonic + */ +function +seed_and_check_bits + (how_many : number) + : Uint8Array +{ +}