Skip to content

Commit

Permalink
fix: ensure module is loaded before consuming as imports
Browse files Browse the repository at this point in the history
  • Loading branch information
PhearZero committed Oct 15, 2024
1 parent 6a9fd5c commit 39131e1
Show file tree
Hide file tree
Showing 9 changed files with 1,314 additions and 949 deletions.
8 changes: 8 additions & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { JestConfigWithTsJest } from 'ts-jest';

const jestConfig: JestConfigWithTsJest = {
preset: 'ts-jest/presets/default-esm',
testPathIgnorePatterns: ["src"],
};

export default jestConfig;
34 changes: 4 additions & 30 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
"type": "module",
"scripts": {
"build": "tsc && tsc-alias -p tsconfig.json -f",
"test": "jest --verbose",
"test:cov": "jest --coverage"
"test": "tsc && tsc-alias -p tsconfig.json -f && node --experimental-vm-modules node_modules/.bin/jest",
"test:cov": "tsc && tsc-alias -p tsconfig.json -f && node --experimental-vm-modules node_modules/.bin/jest --coverage"
},
"keywords": [],
"author": "Algorand Foundation",
Expand All @@ -21,12 +21,14 @@
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/git": "^10.0.1",
"@semantic-release/npm": "^12.0.1",
"@types/bn.js": "^5.1.6",
"@types/jest": "^29.5.5",
"@types/libsodium-wrappers-sumo": "^0.7.7",
"@types/node": "^20.7.1",
"semantic-release": "^24.1.1",
"bip32-ed25519": "^0.0.4",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.2",
"tsc-alias": "^1.8.10",
"tweetnacl": "^1.0.3",
"typescript": "^5.2.2"
Expand All @@ -43,34 +45,6 @@
"ts-custom-error": "^3.2.0",
"ts-log": "^2.2.4"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": ".",
"testRegex": ".spec.ts$",
"coverageDirectory": "../test/coverage",
"collectCoverageFrom": [
"**/!(*.module|*.interface|main|repl|exception.filter|logging.interceptor).{ts,js}"
],
"coveragePathIgnorePatterns": [
"/src/migration/"
],
"testEnvironment": "node",
"moduleNameMapper": {
"^(\\.{1,2}/.*)\\.js$": "$1"
},
"transform": {
"^.+\\.tsx?$": [
"ts-jest",
{
"useESM": true
}
]
}
},
"repository": "[email protected]:algorandfoundation/xHD-Wallet-API-ts.git",
"files": [
"dist",
Expand Down
55 changes: 26 additions & 29 deletions src/bip32-ed25519.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import { createHash, createHmac } from "crypto";
import { read } from "fs";

import {
crypto_core_ed25519_add,
crypto_core_ed25519_add,
crypto_scalarmult_ed25519_base_noclamp,
ready
} from "libsodium-wrappers-sumo";
var BN = require("bn.js");
} from "./sumo.js";
import BN from 'bn.js'
import * as util from 'util'

/**
*
* Reference of BIP32-Ed25519 Hierarchical Deterministic Keys over a Non-linear Keyspace (https://acrobat.adobe.com/id/urn:aaid:sc:EU:04fe29b0-ea1a-478b-a886-9bb558a5242a)
*
* @see section V. BIP32-Ed25519: Specification;
*
*
* A) Root keys
*
*
* @param seed - 256 bite seed generated from BIP39 Mnemonic
* @returns - Extended root key (kL, kR, c) where kL is the left 32 bytes of the root key, kR is the right 32 bytes of the root key, and c is the chain code. Total 96 bytes
*/
Expand Down Expand Up @@ -47,7 +46,7 @@ export function fromSeed(seed: Buffer): Uint8Array {

/**
* This function takes an array of up to 256 bits and sets the last g trailing bits to zero
*
*
* @param array - An array of up to 256 bits
* @param g - The number of bits to zero
* @returns - The array with the last g bits set to zero
Expand Down Expand Up @@ -80,25 +79,23 @@ export function trunc_256_minus_g_bits(array: Uint8Array, g: number): Uint8Array

/**
* @see section V. BIP32-Ed25519: Specification;
*
*
* subsections:
*
*
* B) Child Keys
* and
* C) Private Child Key Derivation
*
*
* @param extendedKey - extended key (kL, kR, c) where kL is the left 32 bytes of the root key the scalar (pvtKey). kR is the right 32 bytes of the root key, and c is the chain code. Total 96 bytes
* @param index - index of the child key
* @param g - Defines how many bits to zero in the left 32 bytes of the child key. Standard BIP32-ed25519 derivations use 32 bits.
* @param g - Defines how many bits to zero in the left 32 bytes of the child key. Standard BIP32-ed25519 derivations use 32 bits.
* @returns - (kL, kR, c) where kL is the left 32 bytes of the child key (the new scalar), kR is the right 32 bytes of the child key, and c is the chain code. Total 96 bytes
*/
export async function deriveChildNodePrivate(
extendedKey: Uint8Array,
index: number,
index: number,
g: number = 9
): Promise<Uint8Array> {
await ready // wait for libsodium to be ready

const kL: Buffer = Buffer.from(extendedKey.subarray(0, 32));
const kR: Buffer = Buffer.from(extendedKey.subarray(32, 64));
const cc: Uint8Array = extendedKey.subarray(64, 96);
Expand All @@ -113,23 +110,23 @@ export async function deriveChildNodePrivate(
// ######################################
// Standard BIP32-ed25519 derivation
// #######################################
// zL = kl + 8 * trunc_keep_28_bytes (z_left_hand_side)
// zL = kl + 8 * trunc_keep_28_bytes (z_left_hand_side)
// zR = zr + kr

// ######################################
// Chris Peikert's ammendment to BIP32-ed25519 derivation
// #######################################
// zL = kl + 8 * trunc_256_minus_g_bits (z_left_hand_side, g)
// zL = kl + 8 * trunc_256_minus_g_bits (z_left_hand_side, g)
// Needs to satisfy g >= d + 6
//
// D = 2 ^ d , D is the maximum levels of BIP32 derivations to ensure a more secure key derivation


// Picking g == 9 && d == 3
// 256 - 9 == 247 bits (30 bytes + leftover)
// D = 2 ^ 3 == 8 Max Levels of derivations (Although we only need 5 due to BIP44)

// making sure
// making sure
// g == 9 >= 3 + 6

const zL: Uint8Array = trunc_256_minus_g_bits(zLeft, g);
Expand All @@ -143,15 +140,15 @@ export async function deriveChildNodePrivate(
const zlBigNumMul8 = klBigNum.add(zlBigNum.mul(big8))

// check if zlBigNumMul8 is equal or larger than 2^255
if (zlBigNumMul8.cmp(new BN(2).pow(new BN(255))) >= 0) {
if (zlBigNumMul8.cmp(new BN(2).pow(new BN(255))) >= 0) {
console.log(util.inspect(zlBigNumMul8), { colors: true, depth: null })
throw new Error('zL * 8 is larger than 2^255, which is not safe')
}

const left = klBigNum.add(zlBigNum.mul(big8)).toArrayLike(Buffer, 'le', 32);

let right = new BN(kR, 16, 'le').add(new BN(zRight, 16, 'le')).toArrayLike(Buffer, 'le').slice(0, 32);

const rightBuffer = Buffer.alloc(32);
Buffer.from(right).copy(rightBuffer, 0, 0, right.length) // padding with zeros if needed

Expand All @@ -161,14 +158,14 @@ export async function deriveChildNodePrivate(

/**
* * @see section V. BIP32-Ed25519: Specification;
*
*
* subsections:
*
*
* D) Public Child key
*
*
* @param extendedKey - extend public key (p, c) where p is the public key and c is the chain code. Total 64 bytes
* @param index - unharden index (i < 2^31) of the child key
* @param g - Defines how many bits to zero in the left 32 bytes of the child key. Standard BIP32-ed25519 derivations use 32 bits.
* @param g - Defines how many bits to zero in the left 32 bytes of the child key. Standard BIP32-ed25519 derivations use 32 bits.
* @returns - 64 bytes, being the 32 bytes of the child key (the new public key) followed by the 32 bytes of the chain code
*/
export async function deriveChildNodePublic(extendedKey: Uint8Array, index: number, g: number = 9): Promise<Uint8Array> {
Expand All @@ -185,15 +182,15 @@ export async function deriveChildNodePublic(extendedKey: Uint8Array, index: numb
// Step 1: Compute Z
data[0] = 0x02;
const z: Buffer = createHmac("sha512", cc).update(data).digest();

// Step 2: Compute child public key
const zL: Uint8Array = trunc_256_minus_g_bits(z.subarray(0, 32), g)

// ######################################
// Standard BIP32-ed25519 derivation
// #######################################
// zL = 8 * 28bytesOf(z_left_hand_side)

// ######################################
// Chris Peikert's ammendment to BIP32-ed25519 derivation
// #######################################
Expand All @@ -213,7 +210,7 @@ export async function deriveChildNodePublic(extendedKey: Uint8Array, index: numb
/**
*
* @see section V. BIP32-Ed25519: Specification
*
*
* @param kl - The scalar
* @param cc - chain code
* @param index - non-hardened ( < 2^31 ) index
Expand Down Expand Up @@ -243,7 +240,7 @@ function derivedNonHardened(
/**
*
* @see section V. BIP32-Ed25519: Specification
*
*
* @param kl - The scalar (a.k.a private key)
* @param kr - the right 32 bytes of the root key
* @param cc - chain code
Expand Down
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from './x.hd.wallet.api.crypto'
export * from './bip32-ed25519'
export * from './x.hd.wallet.api.crypto.js'
export * from './bip32-ed25519.js'
21 changes: 21 additions & 0 deletions src/sumo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import pkg from 'libsodium-wrappers-sumo'

await pkg.ready;

export const crypto_core_ed25519_add = pkg.crypto_core_ed25519_add;
export const crypto_core_ed25519_scalar_add = pkg.crypto_core_ed25519_scalar_add
export const crypto_core_ed25519_scalar_mul = pkg.crypto_core_ed25519_scalar_mul
export const crypto_core_ed25519_scalar_reduce = pkg.crypto_core_ed25519_scalar_reduce
export const crypto_hash_sha512 = pkg.crypto_hash_sha512
export const crypto_scalarmult_ed25519_base_noclamp = pkg.crypto_scalarmult_ed25519_base_noclamp
export const crypto_sign_verify_detached = pkg.crypto_sign_verify_detached
export const crypto_sign_ed25519_pk_to_curve25519 = pkg.crypto_sign_ed25519_pk_to_curve25519
export const crypto_scalarmult = pkg.crypto_scalarmult
export const crypto_generichash = pkg.crypto_generichash
export const crypto_sign_keypair = pkg.crypto_sign_keypair
export const crypto_sign_ed25519_sk_to_curve25519 = pkg.crypto_sign_ed25519_sk_to_curve25519
export const crypto_secretbox_open_easy = pkg.crypto_secretbox_open_easy
export const crypto_secretbox_easy = pkg.crypto_secretbox_easy
export const crypto_kx_client_session_keys = pkg.crypto_kx_client_session_keys
export const crypto_kx_server_session_keys = pkg.crypto_kx_server_session_keys
export const to_base64 = pkg.to_base64
Loading

0 comments on commit 39131e1

Please sign in to comment.