diff --git a/src/basex.mjs b/src/basex.mjs index 6f011a58024389ec99969c3b4e3fda9b3b61d37c..67c4bddafd6b2f4bbb5f0d97247ea4ee0a1c0527 100644 --- a/src/basex.mjs +++ b/src/basex.mjs @@ -1,12 +1,31 @@ // Inspired by bs58, base-x then @thi.ng/base-n module const B58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; -const B64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' +const B64_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' // Padding '=' -export const b64 = basex(B64_ALPHABET); export const b58 = basex(B58_ALPHABET); export const b16 = basex('0123456789abcdef'); export default basex; +const _b64 = basex(B64_ALPHABET); +export const b64 = { + encode:(source)=>{ + const size = Math.ceil(source.length/3)*3; + const sizedArray = new Uint8Array(size); + + if(typeof source === 'string') sizedArray.set((new TextEncoder()).encode(source)); + else sizedArray.set(source); + + const b64str = _b64.encode(sizedArray).split(''); + for(let i = 0;i<size-source.length;i++) b64str[b64str.length-1-i] = '='; + return b64str.join(''); + }, + decode:(b64str)=> { + const rawArray = _b64.decode(b64str.replace(/=/g,'A')); + const targetSize = Math.trunc(3*b64str.length/4 - ( b64str.length - b64str.replace(/=/g,'').length )); + return rawArray.slice(0,targetSize); + } +} + export function basex(ALPHABET) { const config = { ALPHABET_MAP: {}, diff --git a/src/basex.test.mjs b/src/basex.test.mjs index 2cf198c16b3cb57a76f60b644587266fdfc408aa..9befbb437e2fd33bcf5e291e6ab249b3088680e9 100644 --- a/src/basex.test.mjs +++ b/src/basex.test.mjs @@ -4,27 +4,21 @@ import * as app from './basex.mjs'; // Base58 const pubKey = 'AoxVA41dGL2s4ogMNdbCw3FFYjFo5FPK36LuiW1tjGbG'; -test('b58 should decode/encode well', t => { - t.is(app.b58.encode(app.b58.decode(pubKey)), pubKey); -}); -test('basex dont allow ambigous alphabet (each character must be unique)', t => { - t.throws(() => app.basex('zz')); -}); -test('empty input empty output', t => { - t.is(app.b58.encode([]), ''); -}); -test('encode 0000 filled source', t => { - t.is(app.b16.encode([0, 0, 0, 0, 15]), '0000f'); -}); -test('decode 0000 filled source', t => { - t.deepEqual(app.b16.decode('0000f'), new Uint8Array([0, 0, 0, 0, 15])); -}); -test('decode out of base chr throw error', t => { - t.throws(() => app.b58.decode(pubKey + '§')); -}); -test('no string decode throw', t => { - t.throws(() => app.b58.decode([])); -}); -test('decode empty string => empty array', t => { - t.deepEqual(app.b16.decode(''), new Uint8Array(0)); -}); +test('b58 should decode/encode well', t => t.is(app.b58.encode(app.b58.decode(pubKey)), pubKey)); +test('basex dont allow ambigous alphabet (each character must be unique)', t => t.throws(() => app.basex('zz'))); +test('empty input empty output', t => t.is(app.b58.encode([]), '')); +test('decode out of base chr throw error', t => t.throws(() => app.b58.decode(pubKey + '§'))); +test('no string decode throw', t => t.throws(() => app.b58.decode([]))); + +test('encode 0000 filled source', t => t.is(app.b16.encode([0, 0, 0, 0, 15]), '0000f')); +test('decode 0000 filled source', t => t.deepEqual(app.b16.decode('0000f'), new Uint8Array([0, 0, 0, 0, 15]))); +test('decode empty string => empty array', t => t.deepEqual(app.b16.decode(''), new Uint8Array(0))); + +test('b64 should encode Man as TWFu', t => t.is(app.b64.encode('Man'), 'TWFu')); +test('b64 should encode Ma as TWE=', t => t.is(app.b64.encode('Ma'), 'TWE=')); +test('b64 should encode M as TQ==', t => t.is(app.b64.encode('M'), 'TQ==')); +test('b64 should decode TWFu as Man', t => t.is((new TextDecoder()).decode(app.b64.decode('TWFu')), 'Man')); +test('b64 should decode TWE= as Ma', t => t.is((new TextDecoder()).decode(app.b64.decode('TWE=')), 'Ma')); +// Won't fix test('b64 should decode TWE as Ma', t => t.is((new TextDecoder()).decode(app.b64.decode('TWE')), 'Ma')); +test('b64 should decode TQ== as M', t => t.is((new TextDecoder()).decode(app.b64.decode('TQ==')), 'M')); +// Won't fix test('b64 should decode TQ as M', t => t.is((new TextDecoder()).decode(app.b64.decode('TQ')), 'M')); diff --git a/src/crypto.mjs b/src/crypto.mjs index b6b60b03f6740b1a8a734c9051f542a64cd7aec0..eea4cb85e87fd1f7905b4f9653dabae8848b6505 100644 --- a/src/crypto.mjs +++ b/src/crypto.mjs @@ -2,9 +2,9 @@ // Alt deps : import scrypt from "ecma-nacl/build/lib/scrypt/scrypt.js"; import nacl from '../generated/vendors/nacl.mjs'; // Alt import * as ed25519 from '../node_modules/noble-ed25519/index.mjs'; -import {b58,b64 as _b64} from './basex.mjs'; +import {b58,b64} from './basex.mjs'; -export {b58}; +export {b58,b64}; import sha from '../node_modules/js-sha256/src/sha256.mjs'; const sha256 = sha(); @@ -12,25 +12,6 @@ const sha256 = sha(); const generateKeypair = nacl.sign.keyPair.fromSeed; import scrypt from '../generated/vendors/scrypt.mjs'; -export const b64 = { - encode:(source)=>{ - const size = Math.ceil(source.length/3)*3; - const sizedArray = new Uint8Array(size); - - if(typeof source === 'string') sizedArray.set((new TextEncoder()).encode(source)); - else sizedArray.set(source); - - const b64str = _b64.encode(sizedArray).split(''); - for(let i = 0;i<size-source.length;i++) b64str[b64str.length-1-i] = '='; - return b64str.join(''); - }, - decode:(b64str)=> { - const rawArray = _b64.decode(b64str.replace(/=/g,'A')); - const targetSize = Math.trunc(3*b64str.length/4 - ( b64str.length - b64str.replace(/=/g,'').length )); - return rawArray.slice(0,targetSize); - } -} - export async function idSecPass2rawAll(idSec, pass) { const rawSeed = await saltPass2seed(idSec, pass); const keyPair = await seed2keyPair(rawSeed); diff --git a/src/crypto.test.mjs b/src/crypto.test.mjs index cca871960fcf6d3f3dcfd7ae00a71046dce11e38..f60c4d7d6544880ff19b0766c83356685c451d1c 100644 --- a/src/crypto.test.mjs +++ b/src/crypto.test.mjs @@ -23,15 +23,6 @@ Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855 8BZ2NE/d4YO2rOFpJFZdEYTIoSL4uSX9zo6tacpHBcCIlSlhkHTIHbSJNuzLl9uVBIO0skI7NZPxEYXIJGQYBg==`; test('sign document', async t => t.is(await app.sign(unsignedDocument,secretKey), signedDocument)); -test('b64 should encode Man as TWFu', t => t.is(app.b64.encode('Man'), 'TWFu')); -test('b64 should encode Ma as TWE=', t => t.is(app.b64.encode('Ma'), 'TWE=')); -test('b64 should encode M as TQ==', t => t.is(app.b64.encode('M'), 'TQ==')); -test('b64 should decode TWFu as Man', t => t.is((new TextDecoder()).decode(app.b64.decode('TWFu')), 'Man')); -test('b64 should decode TWE= as Ma', t => t.is((new TextDecoder()).decode(app.b64.decode('TWE=')), 'Ma')); -// Won't fix test('b64 should decode TWE as Ma', t => t.is((new TextDecoder()).decode(app.b64.decode('TWE')), 'Ma')); -test('b64 should decode TQ== as M', t => t.is((new TextDecoder()).decode(app.b64.decode('TQ==')), 'M')); -// Won't fix test('b64 should decode TQ as M', t => t.is((new TextDecoder()).decode(app.b64.decode('TQ')), 'M')); - test('b58 should decode/encode well', t => t.is(app.b58.encode(app.b58.decode(pubKey)), pubKey)); test('b58 on pubKey with leading 1', t => t.is(app.b58.encode(app.b58.decode('12BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx')), '12BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx')); test('b58 on pubKey without leading 1', t => t.is(app.b58.encode(app.b58.decode('2BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx')), '2BjyvjoAf5qik7R8TKDJAHJugsX23YgJGi2LmBUv2nx'));