Skip to content
This repository has been archived by the owner on Aug 24, 2021. It is now read-only.

feat: more encoding, errors, spec tests #55

Merged
merged 11 commits into from
Jun 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ jobs:
include:
- stage: check
script:
- npx aegir commitlint --travis
vmx marked this conversation as resolved.
Show resolved Hide resolved
- npx aegir dep-check
- npm run lint

Expand Down
114 changes: 22 additions & 92 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@ js-multibase
## Table of Contents

- [Install](#install)
- [In Node.js through npm](#in-nodejs-through-npm)
- [Browser: Browserify, Webpack, other bundlers](#browser-browserify-webpack-other-bundlers)
- [NPM](#npm)
- [In the Browser through `<script>` tag](#in-the-browser-through-script-tag)
- [Gotchas](#gotchas)
- [Usage](#usage)
- [Example](#example)
- [API](#api)
Expand All @@ -37,10 +35,10 @@ js-multibase

## Install

### In Node.js through npm
### NPM

```bash
> npm install --save multibase
```sh
$ npm install --save multibase
```

The type definitions for this package are available on http://definitelytyped.org/. To install just use:
Expand All @@ -49,23 +47,12 @@ The type definitions for this package are available on http://definitelytyped.or
$ npm install -D @types/multibase
```

### Browser: Browserify, Webpack, other bundlers

The code published to npm that gets loaded on require is in fact an ES5 transpiled version with the right shims added. This means that you can require it and use with your favourite bundler without having to adjust asset management process.

```js
const multibase = require('multibase')
```


### In the Browser through `<script>` tag

Loading this module through a script tag will make the ```Multibase``` obj available in the global namespace.

```html
<script src="https://unpkg.com/multibase/dist/index.min.js"></script>
<!-- OR -->
<script src="https://unpkg.com/multibase/dist/index.js"></script>
```

## Usage
Expand All @@ -86,111 +73,54 @@ console.log(decodedBuf.toString())
## API
https://multiformats.github.io/js-multibase/

### `multibase` - Prefixes an encoded buffer with its multibase code
#### `multibase` - Prefixes an encoded buffer with its multibase code

```
const multibased = multibase(<nameOrCode>, encodedBuf)
```

### `multibase.encode` - Encodes a buffer into one of the supported encodings, prefixing it with the multibase code
#### `multibase.encode` - Encodes a buffer into one of the supported encodings, prefixing it with the multibase code

```JavaScript
const encodedBuf = multibase.encode(<nameOrCode>, <buf>)
```

### `multibase.decode` - Decodes a buffer or string
#### `multibase.decode` - Decodes a buffer or string

```JavaScript
const decodedBuf = multibase.decode(bufOrString)
```

### `multibase.isEncoded` - Checks if buffer or string is encoded
#### `multibase.isEncoded` - Checks if buffer or string is encoded

```JavaScript
const value = multibase.isEncoded(bufOrString)
// value is the name of the encoding if it is encoded, false otherwise
```

### `multibase.names`

A frozen `Array` of supported base encoding names.

### `multibase.codes`

A frozen `Array` of supported base encoding codes.
#### `multibase.encoding` - Get the encoding by name or code

### Supported Encodings, see [`src/constants.js`](/src/constants.js)

## Architecture and Encoding/Decoding

Multibase package defines all the supported bases and the location of their implementation in the constants.js file. A base is a class with a name, a code, an implementation and an alphabet.
```js
class Base {
constructor (name, code, implementation, alphabet) {
//...
}
// ...
}
```JavaScript
const value = multibase.encoding(nameOrCode)
// value is an instance of the corresponding `Base`
```
The ```implementation``` is an object where the encoding/decoding functions are implemented. It must take one argument, (the alphabet) following the [base-x module](https://github.com/cryptocoinjs/base-x) architecture.

The ```alphabet``` is the **ordered** set of defined symbols for a given base.

The idea behind this is that several bases may have implementations from different locations/modules so it's useful to have an object (and a summary) of all of them in one location (hence the constants.js).
#### `multibase.encodingFromData` - Get the encoding from data either a `string` or `Buffer`

All the supported bases are currently using the npm [base-x](https://github.com/cryptocoinjs/base-x) module as their implementation. It is using bitwise maipulation to go from one base to another, so this module does not support padding at the moment.
```JavaScript
const value = multibase.encodingFromData(data)
// value is an instance of the corresponding `Base`
```

## Adding additional bases
#### `multibase.names`

If the base you are looking for is not supported yet in js-multibase and you know a good encoding/decoding algorithm, you can add support for this base easily by editing the constants.js file
(**you'll need to create an issue about that beforehand since a code and a canonical name have to be defined**):
A frozen `Object` of supported base encoding names mapped to the corresponding `Base` instance.

```js
const baseX = require('base-x')
//const newPackage = require('your-package-name')
#### `multibase.codes`

const constants = [
['base2', '0', baseX, '01'],
['base8', '7', baseX, '01234567'],
// ... [ 'your-base-name', 'code-to-be-defined', newPackage, 'alphabet']
]
```
The required package defines the implementation of the encoding/decoding process. **It must comply by these rules** :
- `encode` and `decode` functions with to-be-encoded buffer as the only expected argument
- the require call use the `alphabet` given as an argument for the encoding/decoding process

*If no package is specified , it means the base is not implemented yet*

Adding a new base requires the tests to be updated. Test files to be updated are :
- constants.spec.js
```js
describe('constants', () => {
it('constants indexed by name', () => {
const names = constants.names
expect(Object.keys(names).length).to.equal(constants-count) // currently 12
})

it('constants indexed by code', () => {
const codes = constants.codes
expect(Object.keys(codes).length).to.equal(constants-count)
})
})
```
A frozen `Object` of supported base encoding codes mapped to the corresponding `Base` instance.

- multibase.spec.js
- if the base is implemented
```js
const supportedBases = [
['base2', 'yes mani !', '01111001011001010111001100100000011011010110000101101110011010010010000000100001'],
['base8', 'yes mani !', '7171312714403326055632220041'],
['base10', 'yes mani !', '9573277761329450583662625'],
// ... ['your-base-name', 'what you want', 'expected output']
```
- if the base is not implemented yet
```js
const supportedBases = [
// ... ['your-base-name']
```
### Supported Encodings, see [`src/constants.js`](/src/constants.js)

## Contribute

Expand Down
23 changes: 23 additions & 0 deletions benchmark.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* eslint-disable no-console */
'use strict'
const Benchmark = require('benchmark')
const multibase = require('./src')

const names = Object.keys(multibase.names)
const suite = new Benchmark.Suite()
const input = 'Decentralize everything!!'

for (const enc of names) {
suite.add(enc, () => {
multibase.encode(enc, Buffer.from(input))
})
}

suite
.on('cycle', function (event) {
console.log(String(event.target))
})
.on('complete', function () {
console.log('Fastest is ' + this.filter('fastest').map('name'))
})
.run({ async: true })
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
},
"devDependencies": {
"aegir": "^22.0.0",
"benchmark": "^2.1.4",
"chai": "^4.1.2",
"dirty-chai": "^2.0.1",
"pre-commit": "^1.2.2"
Expand Down
22 changes: 11 additions & 11 deletions src/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@ class Base {
constructor (name, code, implementation, alphabet) {
this.name = name
this.code = code
this.codeBuf = Buffer.from(this.code)
this.alphabet = alphabet
if (implementation && alphabet) {
this.engine = implementation(alphabet)
}
}

encode (stringOrBuffer) {
return this.engine.encode(stringOrBuffer)
this.engine = implementation(alphabet)
}

decode (stringOrBuffer) {
return this.engine.decode(stringOrBuffer)
encode (buf) {
return this.engine.encode(buf)
}

isImplemented () {
return this.engine
decode (string) {
for (const char of string) {
if (this.alphabet && this.alphabet.indexOf(char) < 0) {
throw new Error(`invalid character '${char}' in '${string}'`)
}
}
return this.engine.decode(string)
}
}

Expand Down
21 changes: 0 additions & 21 deletions src/base16.js

This file was deleted.

81 changes: 0 additions & 81 deletions src/base32.js

This file was deleted.

Loading