diff --git a/.gitignore b/.gitignore index d5f19d8..c8c6820 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ node_modules package-lock.json +dist +.nyc_output +coverage diff --git a/.nycrc b/.nycrc new file mode 100644 index 0000000..b54064b --- /dev/null +++ b/.nycrc @@ -0,0 +1,3 @@ +{ + "extends": "@ethereumjs/config-nyc" +} diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..732234f --- /dev/null +++ b/.prettierignore @@ -0,0 +1,6 @@ +node_modules +.vscode +package.json +dist +.nyc_output +docs diff --git a/README.md b/README.md index 8170190..4259245 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,15 @@ -# SYNOPSIS +# SYNOPSIS + [![NPM Package](https://img.shields.io/npm/v/fixed-bn.js.svg?style=flat-square)](https://www.npmjs.org/package/fixed-bn.js) [![Build Status](https://img.shields.io/travis/ewasm/fixed-bn.js.svg?branch=master&style=flat-square)](https://travis-ci.org/ewasm/fixed-bn.js) [![Coverage Status](https://img.shields.io/coveralls/ewasm/fixed-bn.js.svg?style=flat-square)](https://coveralls.io/r/ewasm/fixed-bn.js) -[![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard) +[![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard) a bn.js factory wrapper that constrains numbers to a fixed width # USAGE + ```javascript const FixedBN = require('fixed-bn.js') @@ -22,85 +24,88 @@ bnNum.toBuffer() // you can also create an arbitary fixed lenght bn // max bit lenght is 199 bits and min length is 2 bits -const I199 = FixedBN(199, 2) +const I199 = FixedBN(199, 2) const newBnNum = new I199(390248) ``` # API -Since this module extends [BN.js](https://github.com/indutny/bn.js/) it has the methods as it does plus a few extras. +Since this module extends [BN.js](https://github.com/indutny/bn.js/) it has the methods as it does plus a few extras. ## factory -[./index.js:11-87](https://github.com/ewasm/fixedBN/blob/814e88711940f48efc341ed0c1296f7fa6cdd111/./index.js#L11-L87 "Source code on GitHub") +[./index.js:11-87](https://github.com/ewasm/fixedBN/blob/814e88711940f48efc341ed0c1296f7fa6cdd111/./index.js#L11-L87 'Source code on GitHub') A factory that produces BN.js constructors for a given width **Parameters** -- `maxWidth` **Integer** the max length in bits that the bn.js instance can handle -- `minWidth` **Integer** the min length in bits that the bn.js instance can handle +- `maxWidth` **Integer** the max length in bits that the bn.js instance can handle +- `minWidth` **Integer** the min length in bits that the bn.js instance can handle Returns **bn.js** returns a bn.js constuctor that that is constained to `maxWidth` and `minWidth` ## builtin length + the factory has the following builtins + - `FixedBN.U64` - `FixedBN.U128` - `FixedBN.U160` - `FixedBN.U256` ## bn.js instance + Each instance has the following additional methods ## maxWidth -[./index.js:35-37](https://github.com/ewasm/fixedBN/blob/814e88711940f48efc341ed0c1296f7fa6cdd111/./index.js#L35-L37 "Source code on GitHub") +[./index.js:35-37](https://github.com/ewasm/fixedBN/blob/814e88711940f48efc341ed0c1296f7fa6cdd111/./index.js#L35-L37 'Source code on GitHub') retuns Max Width -Returns **integer** +Returns **integer** ## minWidth -[./index.js:43-45](https://github.com/ewasm/fixedBN/blob/814e88711940f48efc341ed0c1296f7fa6cdd111/./index.js#L43-L45 "Source code on GitHub") +[./index.js:43-45](https://github.com/ewasm/fixedBN/blob/814e88711940f48efc341ed0c1296f7fa6cdd111/./index.js#L43-L45 'Source code on GitHub') retuns Min Width -Returns **integer** +Returns **integer** ## fromBuffer -[./index.js:66-68](https://github.com/ewasm/fixedBN/blob/814e88711940f48efc341ed0c1296f7fa6cdd111/./index.js#L66-L68 "Source code on GitHub") +[./index.js:66-68](https://github.com/ewasm/fixedBN/blob/814e88711940f48efc341ed0c1296f7fa6cdd111/./index.js#L66-L68 'Source code on GitHub') converts a buffer to a fixed-bn.js **Parameters** -- `value` **([string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) | integer)** -- `endain` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** -- `endian` (optional, default `'be'`) +- `value` **([string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) | integer)** +- `endain` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** +- `endian` (optional, default `'be'`) ## isFixBN -[./index.js:74-76](https://github.com/ewasm/fixedBN/blob/814e88711940f48efc341ed0c1296f7fa6cdd111/./index.js#L74-L76 "Source code on GitHub") +[./index.js:74-76](https://github.com/ewasm/fixedBN/blob/814e88711940f48efc341ed0c1296f7fa6cdd111/./index.js#L74-L76 'Source code on GitHub') checks if a BN instance is a fixed BN instance **Parameters** -- `bn` **bn.js** +- `bn` **bn.js** ## isSameWidth -[./index.js:82-84](https://github.com/ewasm/fixedBN/blob/814e88711940f48efc341ed0c1296f7fa6cdd111/./index.js#L82-L84 "Source code on GitHub") +[./index.js:82-84](https://github.com/ewasm/fixedBN/blob/814e88711940f48efc341ed0c1296f7fa6cdd111/./index.js#L82-L84 'Source code on GitHub') checks if a fixed-bn instance is the same width as the contructor **Parameters** -- `fixBN` **bn.js** - +- `fixBN` **bn.js** # LICENSE -[MPL-2.0](https://tldrlegal.com/license/mozilla-public-license-2.0-(mpl-2)) + +[MPL-2.0]() diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..e13e574 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,74 @@ + +# fixed-bn.js + +## Index + +### Classes + +* [Factory](classes/factory.md) +* [FixedWidthBN](classes/fixedwidthbn.md) + +### Type aliases + +* [Endianness](#endianness) + +### Variables + +* [U128](#u128) +* [U160](#u160) +* [U256](#u256) +* [U64](#u64) + +--- + +## Type aliases + + + +### Endianness + +**Ƭ Endianness**: *"le" \| "be"* + +*Defined in [fixed-width.ts:6](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L6)* + +___ + +## Variables + + + +### `` U128 + +**● U128**: *[Factory](classes/factory.md)* = new Factory(128) + +*Defined in [index.ts:7](https://github.com/ewasm/fixed-bn.js/blob/master/src/index.ts#L7)* + +___ + + +### `` U160 + +**● U160**: *[Factory](classes/factory.md)* = new Factory(160) + +*Defined in [index.ts:8](https://github.com/ewasm/fixed-bn.js/blob/master/src/index.ts#L8)* + +___ + + +### `` U256 + +**● U256**: *[Factory](classes/factory.md)* = new Factory(256) + +*Defined in [index.ts:6](https://github.com/ewasm/fixed-bn.js/blob/master/src/index.ts#L6)* + +___ + + +### `` U64 + +**● U64**: *[Factory](classes/factory.md)* = new Factory(64) + +*Defined in [index.ts:9](https://github.com/ewasm/fixed-bn.js/blob/master/src/index.ts#L9)* + +___ + diff --git a/docs/classes/factory.md b/docs/classes/factory.md new file mode 100644 index 0000000..871bdf9 --- /dev/null +++ b/docs/classes/factory.md @@ -0,0 +1,134 @@ +[fixed-bn.js](../README.md) > [Factory](../classes/factory.md) + +# Class: Factory + +Convenience class for creating FixedWidthBN values with the same width. + +## Hierarchy + +**Factory** + +## Index + +### Constructors + +* [constructor](factory.md#constructor) + +### Properties + +* [width](factory.md#width) + +### Methods + +* [fromBN](factory.md#frombn) +* [fromBuffer](factory.md#frombuffer) +* [fromNumber](factory.md#fromnumber) +* [fromString](factory.md#fromstring) + +--- + +## Constructors + + + +### constructor + +⊕ **new Factory**(width: *`number`*): [Factory](factory.md) + +*Defined in [factory.ts:9](https://github.com/ewasm/fixed-bn.js/blob/master/src/factory.ts#L9)* + +**Parameters:** + +| Name | Type | +| ------ | ------ | +| width | `number` | + +**Returns:** [Factory](factory.md) + +___ + +## Properties + + + +### width + +**● width**: *`number`* + +*Defined in [factory.ts:9](https://github.com/ewasm/fixed-bn.js/blob/master/src/factory.ts#L9)* + +___ + +## Methods + + + +### fromBN + +▸ **fromBN**(value: *`BN`*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [factory.ts:19](https://github.com/ewasm/fixed-bn.js/blob/master/src/factory.ts#L19)* + +**Parameters:** + +| Name | Type | +| ------ | ------ | +| value | `BN` | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### fromBuffer + +▸ **fromBuffer**(value: *`Buffer`*, endian?: *[Endianness](../#endianness)*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [factory.ts:27](https://github.com/ewasm/fixed-bn.js/blob/master/src/factory.ts#L27)* + +**Parameters:** + +| Name | Type | Default value | +| ------ | ------ | ------ | +| value | `Buffer` | - | +| `Default value` endian | [Endianness](../#endianness) | "be" | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### fromNumber + +▸ **fromNumber**(value: *`number`*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [factory.ts:15](https://github.com/ewasm/fixed-bn.js/blob/master/src/factory.ts#L15)* + +**Parameters:** + +| Name | Type | +| ------ | ------ | +| value | `number` | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### fromString + +▸ **fromString**(value: *`string`*, base?: *`number`*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [factory.ts:23](https://github.com/ewasm/fixed-bn.js/blob/master/src/factory.ts#L23)* + +**Parameters:** + +| Name | Type | Default value | +| ------ | ------ | ------ | +| value | `string` | - | +| `Default value` base | `number` | 16 | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + diff --git a/docs/classes/fixedwidthbn.md b/docs/classes/fixedwidthbn.md new file mode 100644 index 0000000..090c8d2 --- /dev/null +++ b/docs/classes/fixedwidthbn.md @@ -0,0 +1,889 @@ +[fixed-bn.js](../README.md) > [FixedWidthBN](../classes/fixedwidthbn.md) + +# Class: FixedWidthBN + +A [BN](https://github.com/indutny/bn.js) wrapper that limits numbers to a fixed width. The width should be a factor of 8, and the number is limited to be only unsigned currently. + +## Hierarchy + +**FixedWidthBN** + +## Index + +### Constructors + +* [constructor](fixedwidthbn.md#constructor) + +### Properties + +* [_bn](fixedwidthbn.md#_bn) +* [_modulus](fixedwidthbn.md#_modulus) +* [_width](fixedwidthbn.md#_width) + +### Accessors + +* [modulus](fixedwidthbn.md#modulus) +* [width](fixedwidthbn.md#width) + +### Methods + +* [add](fixedwidthbn.md#add) +* [addMod](fixedwidthbn.md#addmod) +* [and](fixedwidthbn.md#and) +* [bitLength](fixedwidthbn.md#bitlength) +* [clone](fixedwidthbn.md#clone) +* [cmp](fixedwidthbn.md#cmp) +* [div](fixedwidthbn.md#div) +* [eq](fixedwidthbn.md#eq) +* [gt](fixedwidthbn.md#gt) +* [gte](fixedwidthbn.md#gte) +* [hasSameWidth](fixedwidthbn.md#hassamewidth) +* [isEven](fixedwidthbn.md#iseven) +* [isOdd](fixedwidthbn.md#isodd) +* [isZero](fixedwidthbn.md#iszero) +* [lt](fixedwidthbn.md#lt) +* [lte](fixedwidthbn.md#lte) +* [mod](fixedwidthbn.md#mod) +* [mul](fixedwidthbn.md#mul) +* [mulMod](fixedwidthbn.md#mulmod) +* [not](fixedwidthbn.md#not) +* [or](fixedwidthbn.md#or) +* [pow](fixedwidthbn.md#pow) +* [powMod](fixedwidthbn.md#powmod) +* [shl](fixedwidthbn.md#shl) +* [shr](fixedwidthbn.md#shr) +* [sqr](fixedwidthbn.md#sqr) +* [sqrMod](fixedwidthbn.md#sqrmod) +* [sub](fixedwidthbn.md#sub) +* [subMod](fixedwidthbn.md#submod) +* [toArray](fixedwidthbn.md#toarray) +* [toBN](fixedwidthbn.md#tobn) +* [toBuffer](fixedwidthbn.md#tobuffer) +* [toNumber](fixedwidthbn.md#tonumber) +* [toString](fixedwidthbn.md#tostring) +* [xor](fixedwidthbn.md#xor) +* [fromBN](fixedwidthbn.md#frombn) +* [fromBuffer](fixedwidthbn.md#frombuffer) +* [fromString](fixedwidthbn.md#fromstring) + +--- + +## Constructors + + + +### constructor + +⊕ **new FixedWidthBN**(width: *`number`*, value?: *`number`*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:16](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L16)* + +Instantiate a FixedWidthBN given width and a number value. + +*__throws__*: if width < 1 + +*__throws__*: if width % 8 !== 0 + +**Parameters:** + +| Name | Type | Default value | Description | +| ------ | ------ | ------ | ------ | +| width | `number` | - | Width of number in number of bits | +| `Default value` value | `number` | 0 | Value | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + +## Properties + + + +### _bn + +**● _bn**: *`BN`* + +*Defined in [fixed-width.ts:15](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L15)* + +___ + + +### _modulus + +**● _modulus**: *`BN`* + +*Defined in [fixed-width.ts:16](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L16)* + +___ + + +### _width + +**● _width**: *`number`* + +*Defined in [fixed-width.ts:14](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L14)* + +___ + +## Accessors + + + +### modulus + +**get modulus**(): `BN` + +*Defined in [fixed-width.ts:96](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L96)* + +**Returns:** `BN` + +___ + + +### width + +**get width**(): `number` + +*Defined in [fixed-width.ts:92](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L92)* + +Width of number in number of bits. Note that this doesn't necessarily equate the current bit length of the number. + +**Returns:** `number` + +___ + +## Methods + + + +### add + +▸ **add**(b: *[FixedWidthBN](fixedwidthbn.md)*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:261](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L261)* + +Returns a new FixedWidthBN computed from adding value with `b`. + +*__throws__*: if `b` has a different width + +*__throws__*: if add overflows the width + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| b | [FixedWidthBN](fixedwidthbn.md) | Second operand | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### addMod + +▸ **addMod**(b: *[FixedWidthBN](fixedwidthbn.md)*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:273](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L273)* + +Returns a new FixedWidthBN computed from adding value with `b`. It wraps the result on overflow. + +*__throws__*: if `b` has a different width + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| b | [FixedWidthBN](fixedwidthbn.md) | Second operand | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### and + +▸ **and**(b: *[FixedWidthBN](fixedwidthbn.md)*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:405](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L405)* + +Returns a new FixedWidthBN computed from applying a bitwise and. + +*__throws__*: if `b` has a different width + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| b | [FixedWidthBN](fixedwidthbn.md) | Second operand | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### bitLength + +▸ **bitLength**(): `number` + +*Defined in [fixed-width.ts:163](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L163)* + +Returns bit length of value. + +**Returns:** `number` + +___ + + +### clone + +▸ **clone**(): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:155](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L155)* + +Clones value. + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### cmp + +▸ **cmp**(b: *[FixedWidthBN](fixedwidthbn.md)*): `number` + +*Defined in [fixed-width.ts:200](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L200)* + +Compares numbers and returns -1 (a < b), 0 (a == b) or 1 (a > b). + +*__throws__*: if `b` has a different width + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| b | [FixedWidthBN](fixedwidthbn.md) | Value to be compared against | + +**Returns:** `number` + +___ + + +### div + +▸ **div**(b: *[FixedWidthBN](fixedwidthbn.md)*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:372](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L372)* + +Returns a new FixedWidthBN computed from dividing value by `b`. + +*__throws__*: if `b` has a different width + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| b | [FixedWidthBN](fixedwidthbn.md) | Divisor | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### eq + +▸ **eq**(b: *[FixedWidthBN](fixedwidthbn.md)*): `boolean` + +*Defined in [fixed-width.ts:250](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L250)* + +Returns true if value is equal to `b`. + +*__throws__*: if `b` has a different width + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| b | [FixedWidthBN](fixedwidthbn.md) | Value to be compared against | + +**Returns:** `boolean` + +___ + + +### gt + +▸ **gt**(b: *[FixedWidthBN](fixedwidthbn.md)*): `boolean` + +*Defined in [fixed-width.ts:230](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L230)* + +Returns true if value is greated than `b`. + +*__throws__*: if `b` has a different width + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| b | [FixedWidthBN](fixedwidthbn.md) | Value to be compared against | + +**Returns:** `boolean` + +___ + + +### gte + +▸ **gte**(b: *[FixedWidthBN](fixedwidthbn.md)*): `boolean` + +*Defined in [fixed-width.ts:240](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L240)* + +Returns true if value is greated than or equal to `b`. + +*__throws__*: if `b` has a different width + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| b | [FixedWidthBN](fixedwidthbn.md) | Value to be compared against | + +**Returns:** `boolean` + +___ + + +### hasSameWidth + +▸ **hasSameWidth**(b: *[FixedWidthBN](fixedwidthbn.md)*): `boolean` + +*Defined in [fixed-width.ts:170](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L170)* + +Returns true if `b` has same width (not bit length) as value. + +**Parameters:** + +| Name | Type | +| ------ | ------ | +| b | [FixedWidthBN](fixedwidthbn.md) | + +**Returns:** `boolean` + +___ + + +### isEven + +▸ **isEven**(): `boolean` + +*Defined in [fixed-width.ts:177](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L177)* + +Returns true if number is even. + +**Returns:** `boolean` + +___ + + +### isOdd + +▸ **isOdd**(): `boolean` + +*Defined in [fixed-width.ts:184](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L184)* + +Returns true if number is odd. + +**Returns:** `boolean` + +___ + + +### isZero + +▸ **isZero**(): `boolean` + +*Defined in [fixed-width.ts:191](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L191)* + +Returns true if number is zero. + +**Returns:** `boolean` + +___ + + +### lt + +▸ **lt**(b: *[FixedWidthBN](fixedwidthbn.md)*): `boolean` + +*Defined in [fixed-width.ts:210](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L210)* + +Returns true if value is less than `b`. + +*__throws__*: if `b` has a different width + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| b | [FixedWidthBN](fixedwidthbn.md) | Value to be compared against | + +**Returns:** `boolean` + +___ + + +### lte + +▸ **lte**(b: *[FixedWidthBN](fixedwidthbn.md)*): `boolean` + +*Defined in [fixed-width.ts:220](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L220)* + +Returns true if value is less than or equal to `b`. + +*__throws__*: if `b` has a different width + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| b | [FixedWidthBN](fixedwidthbn.md) | Value to be compared against | + +**Returns:** `boolean` + +___ + + +### mod + +▸ **mod**(b: *[FixedWidthBN](fixedwidthbn.md)*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:383](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L383)* + +Returns a new FixedWidthBN computed from value mod b. + +*__throws__*: if `b` has a different width + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| b | [FixedWidthBN](fixedwidthbn.md) | Modulus | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### mul + +▸ **mul**(b: *[FixedWidthBN](fixedwidthbn.md)*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:309](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L309)* + +Returns a new FixedWidthBN computed from multiplying value with `b`. + +*__throws__*: if `b` has a different width + +*__throws__*: if mul overflows + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| b | [FixedWidthBN](fixedwidthbn.md) | Second operand | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### mulMod + +▸ **mulMod**(b: *[FixedWidthBN](fixedwidthbn.md)*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:321](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L321)* + +Returns a new FixedWidthBN computed from multiplying value with `b`. It wraps the result on overflow. + +*__throws__*: if `b` has a different width + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| b | [FixedWidthBN](fixedwidthbn.md) | Second operand | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### not + +▸ **not**(): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:445](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L445)* + +Returns a new FixedWidthBN computed from bitwise negation of value. + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### or + +▸ **or**(b: *[FixedWidthBN](fixedwidthbn.md)*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:394](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L394)* + +Returns a new FixedWidthBN computed from applying a bitwise or. + +*__throws__*: if `b` has a different width + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| b | [FixedWidthBN](fixedwidthbn.md) | Second operand | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### pow + +▸ **pow**(b: *[FixedWidthBN](fixedwidthbn.md)*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:351](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L351)* + +Returns a new FixedWidthBN computed from raising value to power of `b`. + +*__throws__*: if `b` has a different width + +*__throws__*: if pow overflows + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| b | [FixedWidthBN](fixedwidthbn.md) | Exponent | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### powMod + +▸ **powMod**(b: *[FixedWidthBN](fixedwidthbn.md)*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:362](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L362)* + +Returns a new FixedWidthBN computed from raising value to power of `b`. It wraps the result on overflow. + +*__throws__*: if `b` has a different width + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| b | [FixedWidthBN](fixedwidthbn.md) | Exponent | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### shl + +▸ **shl**(b: *`number`*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:427](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L427)* + +Returns a new FixedWidthBN computed from shifting value to left by a number of bits. It discards bits that are shifted out of width. + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| b | `number` | Number of bits to shift | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### shr + +▸ **shr**(b: *`number`*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:437](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L437)* + +Returns a new FixedWidthBN computed from shifting value to right by a number of bits. It discards bits that are shifted out of width. + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| b | `number` | Number of bits to shift | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### sqr + +▸ **sqr**(): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:331](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L331)* + +Returns a new FixedWidthBN computed from multiplying value with itself (square of value). + +*__throws__*: if sqr overflows + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### sqrMod + +▸ **sqrMod**(): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:340](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L340)* + +Returns a new FixedWidthBN computed from multiplying value with itself (square of value). It wraps the result on overflow. + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### sub + +▸ **sub**(b: *[FixedWidthBN](fixedwidthbn.md)*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:285](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L285)* + +Returns a new FixedWidthBN computed from subtracting value from `b`. + +*__throws__*: if `b` has a different width + +*__throws__*: if sub underflows + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| b | [FixedWidthBN](fixedwidthbn.md) | Second operand | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### subMod + +▸ **subMod**(b: *[FixedWidthBN](fixedwidthbn.md)*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:297](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L297)* + +Returns a new FixedWidthBN computed from subtracting value from `b`. It wraps the result on underflow, e.g. if width is 8, `2 - 3 == 255`. + +*__throws__*: if `b` has a different width + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| b | [FixedWidthBN](fixedwidthbn.md) | Second operand | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### toArray + +▸ **toArray**(endian?: *[Endianness](../#endianness)*): `number`[] + +*Defined in [fixed-width.ts:119](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L119)* + +Returns number as an array. + +**Parameters:** + +| Name | Type | Default value | Description | +| ------ | ------ | ------ | ------ | +| `Default value` endian | [Endianness](../#endianness) | "be" | Endianness | + +**Returns:** `number`[] + +___ + + +### toBN + +▸ **toBN**(): `BN` + +*Defined in [fixed-width.ts:103](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L103)* + +Returns a normal BN from the FixedWidthBN. + +**Returns:** `BN` + +___ + + +### toBuffer + +▸ **toBuffer**(endian?: *[Endianness](../#endianness)*): `Buffer` + +*Defined in [fixed-width.ts:111](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L111)* + +Returns number as a Buffer. + +**Parameters:** + +| Name | Type | Default value | Description | +| ------ | ------ | ------ | ------ | +| `Default value` endian | [Endianness](../#endianness) | "be" | Endianness | + +**Returns:** `Buffer` + +___ + + +### toNumber + +▸ **toNumber**(): `number` + +*Defined in [fixed-width.ts:127](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L127)* + +Returns value as a Javascript number (limited to 53 bits). + +*__throws__*: if bit length of value is larger than 53 + +**Returns:** `number` + +___ + + +### toString + +▸ **toString**(base?: *`number`*, pad?: *`boolean`*): `string` + +*Defined in [fixed-width.ts:137](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L137)* + +Returns value encoded as a string (without `0x` prefix for base 16). + +**Parameters:** + +| Name | Type | Default value | Description | +| ------ | ------ | ------ | ------ | +| `Default value` base | `number` | 16 | Base for encoding (e.g. 16 for hex) | +| `Default value` pad | `boolean` | true | Pad output string to width (only for bases 2 and 16) | + +**Returns:** `string` + +___ + + +### xor + +▸ **xor**(b: *[FixedWidthBN](fixedwidthbn.md)*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:416](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L416)* + +Returns a new FixedWidthBN computed from applying a bitwise xor. + +*__throws__*: if `b` has a different width + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| b | [FixedWidthBN](fixedwidthbn.md) | Second operand | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### `` fromBN + +▸ **fromBN**(width: *`number`*, value: *`BN`*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:43](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L43)* + +Instantiates from a BN object. + +*__throws__*: if value is not a BN + +*__throws__*: if BN value is larger than the given width + +*__throws__*: if value is negative + +**Parameters:** + +| Name | Type | Description | +| ------ | ------ | ------ | +| width | `number` | Width in number of bits | +| value | `BN` | Value | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### `` fromBuffer + +▸ **fromBuffer**(width: *`number`*, value: *`Buffer`*, endian?: *[Endianness](../#endianness)*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:82](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L82)* + +Instantiates from a buffer. + +*__throws__*: if vlaue is not a buffer + +*__throws__*: if value is larger than given width + +**Parameters:** + +| Name | Type | Default value | Description | +| ------ | ------ | ------ | ------ | +| width | `number` | - | Width in number of bits | +| value | `Buffer` | - | Value | +| `Default value` endian | [Endianness](../#endianness) | "be" | Endianness of number | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + + +### `` fromString + +▸ **fromString**(width: *`number`*, value: *`string`*, base?: *`number`*): [FixedWidthBN](fixedwidthbn.md) + +*Defined in [fixed-width.ts:64](https://github.com/ewasm/fixed-bn.js/blob/master/src/fixed-width.ts#L64)* + +Instantiates from a string. It strips `0x` from beginning of strings. + +*__throws__*: if value is not a string + +*__throws__*: if value is larger than the given width + +**Parameters:** + +| Name | Type | Default value | Description | +| ------ | ------ | ------ | ------ | +| width | `number` | - | Width in number of bits | +| value | `string` | - | Encoded value | +| `Default value` base | `number` | 16 | Base in which number is encoded | + +**Returns:** [FixedWidthBN](fixedwidthbn.md) + +___ + diff --git a/index.js b/index.js deleted file mode 100644 index b4ebcf6..0000000 --- a/index.js +++ /dev/null @@ -1,94 +0,0 @@ -const stripHexPrefix = require('strip-hex-prefix') -const isHexPrefixed = require('is-hex-prefixed') -const BN = require('bn.js') - -/** - * A factory that produces BN.js constructors for a given width - * @param {Integer} maxWidth the max length in bits that the bn.js instance can handle - * @param {Integer} minWidth the min length in bits that the bn.js instance can handle - * @return {bn.js} returns a bn.js constuctor that that is constained to `maxWidth` and `minWidth` - */ -const factory = module.exports = function factory (maxWidth, minWidth = 0) { - class FixWidth extends BN { - constructor (value) { - // bn.js still doesn't support hex prefixes... - if ((typeof value === 'string') && isHexPrefixed(value)) { - super(stripHexPrefix(value), 16) - } else { - super(value, 10) - } - - if (this.byteLength() * 8 > maxWidth) { - throw Error(`number must be less then ${maxWidth} bits`) - } - - if (this.byteLength() * 8 < minWidth) { - throw new Error(`number must be more then ${minWidth} bits`) - } - this._maxWidth = maxWidth - this._minWidth = minWidth - } - - /** - * retuns Max Width - * @returns {integer} - */ - get maxWidth () { - return this._maxWidth - } - - /** - * retuns Min Width - * @returns {integer} - */ - get minWidth () { - return this._minWidth - } - - // This assumes Uint8Array in LSB (WASM code) - toBuffer (endian = 'be') { - return super.toBuffer(endian, this._maxWidth / 8) - } - - toArray (endian) { - return super.toArray(endian, this._maxWidth / 8) - } - - toArrayLike (type, endian) { - return super.toArrayLike(type, endian, this._maxWidth / 8) - } - } - - /** - * converts a buffer to a fixed-bn.js - * @param {string | integer} value - * @param {string} endain - */ - FixWidth.fromBuffer = (value, endian = 'be') => { - return new FixWidth(value, 16, endian) - } - - /** - * checks if a BN instance is a fixed BN instance - * @param {bn.js} bn - */ - FixWidth.isFixBN = (bn) => { - return bn.hasOwnProperty('_minWidth') && bn.hasOwnProperty('_maxWidth') - } - - /** - * checks if a fixed-bn instance is the same width as the contructor - * @param {bn.js} fixBN - */ - FixWidth.isSameWidth = (fixBN) => { - return minWidth === fixBN.minWidth && maxWidth === fixBN.maxWidth - } - - return FixWidth -} - -factory.U256 = factory(256) -factory.U160 = factory(160) -factory.U128 = factory(128) -factory.U64 = factory(64) -factory.Address = factory(160, 160) diff --git a/package.json b/package.json index 3acdbb0..3a11737 100644 --- a/package.json +++ b/package.json @@ -2,12 +2,24 @@ "name": "fixed-bn.js", "version": "0.0.2", "description": "bn.js wrapper that constrains numbers to a fixed width", - "main": "index.js", + "main": "dist/index.js", + "types": "dist/index.d.ts", "scripts": { - "coverage": "istanbul cover ./tests/index.js", - "coveralls": "npm run coverage && coveralls ", "license": "MPL-2.0", "devDependencies": { + "@ethereumjs/config-nyc": "^1.1.1", + "@ethereumjs/config-prettier": "^1.1.1", + "@ethereumjs/config-tsc": "^1.1.1", + "@ethereumjs/config-tslint": "^1.1.1", + "@types/bn.js": "^4.11.4", + "@types/node": "^11.11.3", + "@types/tape": "^4.2.33", "coveralls": "^3.0.0", - "istanbul": "^0.4.5", - "standard": "^11.0.0", - "tape": "^4.6.3" + "nyc": "^13.3.0", + "prettier": "^1.16.4", + "tape": "^4.6.3", + "ts-node": "^8.0.3", + "tslint": "^5.14.0", + "typedoc": "^0.14.2", + "typedoc-plugin-markdown": "^1.1.27", + "typescript": "^3.3.3333", + "typestrict": "^1.0.2" }, "repository": { "type": "git", diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 0000000..0f2e5b7 --- /dev/null +++ b/prettier.config.js @@ -0,0 +1 @@ +module.exports = require('@ethereumjs/config-prettier') diff --git a/src/factory.ts b/src/factory.ts new file mode 100644 index 0000000..d445211 --- /dev/null +++ b/src/factory.ts @@ -0,0 +1,30 @@ +import BN = require('bn.js') +import { FixedWidthBN, Endianness } from './fixed-width' + +/** + * Convenience class for creating FixedWidthBN values + * with the same width. + */ +export class Factory { + width: number + + constructor(width: number) { + this.width = width + } + + fromNumber(value: number): FixedWidthBN { + return new FixedWidthBN(this.width, value) + } + + fromBN(value: BN): FixedWidthBN { + return FixedWidthBN.fromBN(this.width, value) + } + + fromString(value: string, base: number = 16): FixedWidthBN { + return FixedWidthBN.fromString(this.width, value, base) + } + + fromBuffer(value: Buffer, endian: Endianness = 'be'): FixedWidthBN { + return FixedWidthBN.fromBuffer(this.width, value, endian) + } +} diff --git a/src/fixed-width.ts b/src/fixed-width.ts new file mode 100644 index 0000000..1540281 --- /dev/null +++ b/src/fixed-width.ts @@ -0,0 +1,499 @@ +const assert = require('assert') +const stripHexPrefix = require('strip-hex-prefix') +const isHexPrefixed = require('is-hex-prefixed') +import BN = require('bn.js') + +export type Endianness = 'le' | 'be' + +/** + * A [BN](https://github.com/indutny/bn.js) wrapper that limits numbers to + * a fixed width. The width should be a factor of 8, and the number is limited + * to be only unsigned currently. + */ +export class FixedWidthBN { + _width: number + _bn: BN + _modulus: BN + + /** + * Instantiate a FixedWidthBN given width and a number value. + * @param width - Width of number in number of bits + * @param value - Value + * @throws if width < 1 + * @throws if width % 8 !== 0 + */ + constructor(width: number, value: number = 0) { + assert(width >= 1, 'Invalid width') + assert(width % 8 === 0, 'Width should be divisible by 8') + this._width = width + this._bn = new BN(value) + // 2 ** width + // Used for taking modulo, e.g. after addMod, mulMod + this._modulus = new BN(2).pow(new BN(this._width)) + } + + /** + * Instantiates from a BN object. + * @param width - Width in number of bits + * @param value - Value + * @throws if value is not a BN + * @throws if BN value is larger than the given width + * @throws if value is negative + */ + static fromBN(width: number, value: BN): FixedWidthBN { + assert(BN.isBN(value), 'Value should be BN') + assert(value.bitLength() <= width, 'Value exceeds width') + assert(!value.isNeg(), 'Value should be positive') + + const n = new FixedWidthBN(width, 0) + n._width = width + n._bn = value + + return n + } + + /** + * Instantiates from a string. It strips `0x` from beginning + * of strings. + * @param width - Width in number of bits + * @param value - Encoded value + * @param base - Base in which number is encoded + * @throws if value is not a string + * @throws if value is larger than the given width + */ + static fromString(width: number, value: string, base: number = 16): FixedWidthBN { + assert(typeof value === 'string') + if (isHexPrefixed(value)) { + value = stripHexPrefix(value) + } + + const bn = new BN(value, base) + return FixedWidthBN.fromBN(width, bn) + } + + /** + * Instantiates from a buffer. + * @param width - Width in number of bits + * @param value - Value + * @param endian - Endianness of number + * @throws if vlaue is not a buffer + * @throws if value is larger than given width + */ + static fromBuffer(width: number, value: Buffer, endian: Endianness = 'be'): FixedWidthBN { + assert(Buffer.isBuffer(value)) + const bn = new BN(value, 10, endian) + return FixedWidthBN.fromBN(width, bn) + } + + /** + * Width of number in number of bits. Note that this doesn't + * necessarily equate the current bit length of the number. + */ + get width(): number { + return this._width + } + + get modulus(): BN { + return this._modulus + } + + /** + * Returns a normal BN from the FixedWidthBN. + */ + toBN(): BN { + return this._bn + } + + /** + * Returns number as a Buffer. + * @param endian - Endianness + */ + toBuffer(endian: Endianness = 'be', pad: boolean = false): Buffer { + const length = pad ? this._width / 8 : 1 + return this._bn.toBuffer(endian, length) + } + + /** + * Returns number as an array. + * @param endian - Endianness + */ + toArray(endian: Endianness = 'be', pad: boolean = false): number[] { + const length = pad ? this._width / 8 : 1 + return this._bn.toArray(endian, length) + } + + /** + * Returns value as a Javascript number (limited to 53 bits). + * @throws if bit length of value is larger than 53 + */ + toNumber(): number { + assert(this._bn.bitLength() <= 53) + return this._bn.toNumber() + } + + /** + * Returns value encoded as a string (without `0x` prefix for base 16). + * @param base - Base for encoding (e.g. 16 for hex) + * @param pad - Pad output string to width (only for bases 2 and 16) + */ + toString(base: number = 16, pad: boolean = true): string { + if (pad && (base !== 2 && base !== 16)) { + throw new Error('Padding string only supported for bases 2 and 16') + } + + if (pad) { + // BN.toString accepts length as number of chars in output string + // which, e.g. for base 16 is 2 for each byte, and hence: 2 * (bits / 8) + const length = base === 16 ? this._width / 4 : this._width + return this._bn.toString(base, length) + } else { + return this._bn.toString(base) + } + } + + /** + * Clones value. + */ + clone(): FixedWidthBN { + const bn = this._bn.clone() + return FixedWidthBN.fromBN(this._width, bn) + } + + /** + * Returns bit length of value. + */ + bitLength(): number { + return this._bn.bitLength() + } + + /** + * Returns byte length of value. + */ + byteLength(): number { + return this._bn.byteLength() + } + + /** + * Returns true if `b` has same width (not bit length) as value. + */ + hasSameWidth(b: FixedWidthBN): boolean { + return this._width === b._width + } + + /** + * Returns true if number is even. + */ + isEven(): boolean { + return this._bn.isEven() + } + + /** + * Returns true if number is odd. + */ + isOdd(): boolean { + return this._bn.isOdd() + } + + /** + * Returns true if number is zero. + */ + isZero(): boolean { + return this._bn.isZero() + } + + /** + * Compares numbers and returns -1 (a < b), 0 (a == b) or 1 (a > b). + * @param b - Value to be compared against + * @throws if `b` has a different width + */ + cmp(b: FixedWidthBN): number { + assert(this.hasSameWidth(b)) + return this._bn.cmp(b._bn) + } + + /** + * Returns true if value is less than `b`. + * @param b - Value to be compared against + * @throws if `b` has a different width + */ + lt(b: FixedWidthBN): boolean { + assert(this.hasSameWidth(b)) + return this._bn.lt(b._bn) + } + + /** + * Returns true if value is less than or equal to `b`. + * @param b - Value to be compared against + * @throws if `b` has a different width + */ + lte(b: FixedWidthBN): boolean { + assert(this.hasSameWidth(b)) + return this._bn.lte(b._bn) + } + + /** + * Returns true if value is less than `b`. + * @param b - Value to be compared against + */ + ltn(b: number): boolean { + return this._bn.ltn(b) + } + + /** + * Returns true if value is less than or equal to `b`. + * @param b - Value to be compared against + */ + lten(b: number): boolean { + return this._bn.lten(b) + } + + /** + * Returns true if value is greated than `b`. + * @param b - Value to be compared against + * @throws if `b` has a different width + */ + gt(b: FixedWidthBN): boolean { + assert(this.hasSameWidth(b)) + return this._bn.gt(b._bn) + } + + /** + * Returns true if value is greated than or equal to `b`. + * @param b - Value to be compared against + * @throws if `b` has a different width + */ + gte(b: FixedWidthBN): boolean { + assert(this.hasSameWidth(b)) + return this._bn.gte(b._bn) + } + + /** + * Returns true if value is greated than `b`. + * @param b - Value to be compared against + */ + gtn(b: number): boolean { + return this._bn.gtn(b) + } + + /** + * Returns true if value is greated than or equal to `b`. + * @param b - Value to be compared against + * @throws if `b` has a different width + */ + gten(b: number): boolean { + return this._bn.gten(b) + } + + /** + * Returns true if value is equal to `b`. + * @param b - Value to be compared against + * @throws if `b` has a different width + */ + eq(b: FixedWidthBN): boolean { + assert(this.hasSameWidth(b)) + return this._bn.eq(b._bn) + } + + /** + * Returns a new FixedWidthBN computed from adding value with `b`. + * @param b - Second operand + * @throws if `b` has a different width + * @throws if add overflows the width + */ + add(b: FixedWidthBN): FixedWidthBN { + assert(this.hasSameWidth(b)) + const c = this._bn.add(b._bn) + return FixedWidthBN.fromBN(this._width, c) + } + + /** + * Returns a new FixedWidthBN computed from adding value with `b`. + * It wraps the result on overflow. + * @param b - Second operand + * @throws if `b` has a different width + */ + addMod(b: FixedWidthBN): FixedWidthBN { + assert(this.hasSameWidth(b)) + const c = this._bn.add(b._bn).mod(this.modulus) + return FixedWidthBN.fromBN(this._width, c) + } + + /** + * Returns a new FixedWidthBN computed from subtracting value from `b`. + * @param b - Second operand + * @throws if `b` has a different width + * @throws if sub underflows + */ + sub(b: FixedWidthBN): FixedWidthBN { + assert(this.hasSameWidth(b)) + const c = this._bn.sub(b._bn) + return FixedWidthBN.fromBN(this._width, c) + } + + /** + * Returns a new FixedWidthBN computed from subtracting value from `b`. + * It wraps the result on underflow, e.g. if width is 8, `2 - 3 == 255`. + * @param b - Second operand + * @throws if `b` has a different width + */ + subMod(b: FixedWidthBN): FixedWidthBN { + assert(this.hasSameWidth(b)) + const c = this._bn.sub(b._bn).umod(this.modulus) + return FixedWidthBN.fromBN(this._width, c) + } + + /** + * Returns a new FixedWidthBN computed from multiplying value with `b`. + * @param b - Second operand + * @throws if `b` has a different width + * @throws if mul overflows + */ + mul(b: FixedWidthBN): FixedWidthBN { + assert(this.hasSameWidth(b)) + const c = this._bn.mul(b._bn) + return FixedWidthBN.fromBN(this._width, c) + } + + /** + * Returns a new FixedWidthBN computed from multiplying value with `b`. + * It wraps the result on overflow. + * @param b - Second operand + * @throws if `b` has a different width + */ + mulMod(b: FixedWidthBN): FixedWidthBN { + assert(this.hasSameWidth(b)) + const c = this._bn.mul(b._bn).mod(this.modulus) + return FixedWidthBN.fromBN(this._width, c) + } + + /** + * Returns a new FixedWidthBN computed from multiplying value with itself (square of value). + * @throws if sqr overflows + */ + sqr(): FixedWidthBN { + const c = this._bn.sqr() + return FixedWidthBN.fromBN(this._width, c) + } + + /** + * Returns a new FixedWidthBN computed from multiplying value with itself (square of value). + * It wraps the result on overflow. + */ + sqrMod(): FixedWidthBN { + const c = this._bn.sqr().mod(this.modulus) + return FixedWidthBN.fromBN(this._width, c) + } + + /** + * Returns a new FixedWidthBN computed from raising value to power of `b`. + * @param b - Exponent + * @throws if `b` has a different width + * @throws if pow overflows + */ + pow(b: FixedWidthBN): FixedWidthBN { + const c = this._bn.pow(b._bn) + return FixedWidthBN.fromBN(this._width, c) + } + + /** + * Returns a new FixedWidthBN computed from raising value to power of `b`. + * It wraps the result on overflow. + * @param b - Exponent + * @throws if `b` has a different width + */ + powMod(b: FixedWidthBN): FixedWidthBN { + const c = this._bn.pow(b._bn).mod(this.modulus) + return FixedWidthBN.fromBN(this._width, c) + } + + /** + * Returns a new FixedWidthBN computed from dividing value by `b`. + * @param b - Divisor + * @throws if `b` has a different width + */ + div(b: FixedWidthBN): FixedWidthBN { + assert(this.hasSameWidth(b)) + const c = this._bn.div(b._bn) + return FixedWidthBN.fromBN(this._width, c) + } + + /** + * Returns a new FixedWidthBN computed from value mod b. + * @param b - Modulus + * @throws if `b` has a different width + */ + mod(b: FixedWidthBN): FixedWidthBN { + assert(this.hasSameWidth(b)) + const c = this._bn.mod(b._bn) + return FixedWidthBN.fromBN(this._width, c) + } + + /** + * Returns a new FixedWidthBN computed from applying a bitwise or. + * @param b - Second operand + * @throws if `b` has a different width + */ + or(b: FixedWidthBN): FixedWidthBN { + assert(this.hasSameWidth(b)) + const c = this._bn.or(b._bn) + return FixedWidthBN.fromBN(this._width, c) + } + + /** + * Returns a new FixedWidthBN computed from applying a bitwise and. + * @param b - Second operand + * @throws if `b` has a different width + */ + and(b: FixedWidthBN): FixedWidthBN { + assert(this.hasSameWidth(b)) + const c = this._bn.and(b._bn) + return FixedWidthBN.fromBN(this._width, c) + } + + /** + * Returns a new FixedWidthBN computed from applying a bitwise xor. + * @param b - Second operand + * @throws if `b` has a different width + */ + xor(b: FixedWidthBN): FixedWidthBN { + assert(this.hasSameWidth(b)) + const c = this._bn.xor(b._bn) + return FixedWidthBN.fromBN(this._width, c) + } + + /** + * Returns a new FixedWidthBN computed from shifting value to left + * by a number of bits. It discards bits that are shifted out of width. + * @param b - Number of bits to shift + */ + shl(b: number): FixedWidthBN { + const c = this._bn.shln(b).mod(this.modulus) + return FixedWidthBN.fromBN(this._width, c) + } + + /** + * Returns a new FixedWidthBN computed from shifting value to right + * by a number of bits. It discards bits that are shifted out of width. + * @param b - Number of bits to shift + */ + shr(b: number): FixedWidthBN { + const c = this._bn.shrn(b).mod(this.modulus) + return FixedWidthBN.fromBN(this._width, c) + } + + /** + * Tests if a specific bit is set. + * @param b - Index of bit to test + */ + test(b: number): boolean { + return this._bn.testn(b) + } + + /** + * Returns a new FixedWidthBN computed from bitwise negation of value. + */ + not(): FixedWidthBN { + const c = this._bn.notn(this._width) + return FixedWidthBN.fromBN(this._width, c) + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..65f8da6 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,9 @@ +import { Factory } from './factory' + +export { FixedWidthBN } from './fixed-width' +export { Factory } from './factory' + +export const U256 = new Factory(256) +export const U128 = new Factory(128) +export const U160 = new Factory(160) +export const U64 = new Factory(64) diff --git a/tests/factory.ts b/tests/factory.ts new file mode 100644 index 0000000..22aef67 --- /dev/null +++ b/tests/factory.ts @@ -0,0 +1,49 @@ +import * as tape from 'tape' +import BN = require('bn.js') +import { U64, U256 } from '../src' +import { padHexToLength } from './utils' + +tape('Factory types', (t: tape.Test) => { + t.test('should instantiate from number', (st: tape.Test) => { + const n = U256.fromNumber(5) + st.equal(n.width, 256) + st.equal(n.toNumber(), 5) + st.end() + }) + + t.test('should instantiate from BN', (st: tape.Test) => { + // (2 ** 64) - 1 + const hex = 'ffffffffffffffff' + const bn = new BN(hex, 16) + const n = U256.fromBN(bn) + st.equal(n.width, 256) + st.equal(n.toString(), padHexToLength(hex, 256)) + st.end() + }) + + t.test('should instantiate from string', (st: tape.Test) => { + const hex = 'ffffffffffffffff' + const n = U256.fromString(hex) + st.equal(n.toString(), padHexToLength(hex, 256)) + st.end() + }) + + t.test('should instantiate from buffer', (st: tape.Test) => { + const hex = 'ffffffffffffffff' + const buf = Buffer.from([255, 255, 255, 255, 255, 255, 255, 255]) + const n = U64.fromBuffer(buf) + st.equal(n.toString(), padHexToLength(hex, 64)) + st.end() + }) + + t.test('should throw on instantiating when value exceeds width', (st: tape.Test) => { + // (2 ** 72) - 1 + const hex = 'ffffffffffffffffff' + const buf = Buffer.from(hex, 'hex') + const bn = new BN(hex, 16) + st.throws(() => U64.fromBN(bn)) + st.throws(() => U64.fromString(hex)) + st.throws(() => U64.fromBuffer(buf)) + st.end() + }) +}) diff --git a/tests/fixed-width.ts b/tests/fixed-width.ts new file mode 100644 index 0000000..147047f --- /dev/null +++ b/tests/fixed-width.ts @@ -0,0 +1,270 @@ +import * as tape from 'tape' +import BN = require('bn.js') +import { FixedWidthBN } from '../src' +import { padHexToLength } from './utils' + +tape('Constructor', (t: tape.Test) => { + t.test('should instantiate from number', (st: tape.Test) => { + const n = new FixedWidthBN(256, 5) + st.equal(n.width, 256) + st.equal(n.toNumber(), 5) + st.end() + }) + + t.test('should not construct with invalid width', (st: tape.Test) => { + st.throws(() => new FixedWidthBN(255, 5)) + st.end() + }) +}) + +tape('Comparison', (t: tape.Test) => { + t.test('should compare two same width BNs', (st: tape.Test) => { + const a = new FixedWidthBN(64, 21) + const b = new FixedWidthBN(64, 20) + const c = 99 + const d = 21 + st.equal(a.lt(b), false) + st.equal(a.lte(b), false) + st.equal(a.gt(b), true) + st.equal(a.gte(b), true) + st.equal(a.eq(b), false) + st.equal(a.ltn(c), true) + st.equal(a.lten(c), true) + st.equal(a.lten(d), true) + st.equal(a.gtn(c), false) + st.equal(a.gten(c), false) + st.equal(a.gten(d), true) + st.end() + }) + + t.test('should throw on comparing BNs with varying width', (st: tape.Test) => { + const a = new FixedWidthBN(64, 21) + const b = new FixedWidthBN(56, 20) + st.throws(() => a.lt(b)) + st.throws(() => a.lte(b)) + st.throws(() => a.gt(b)) + st.throws(() => a.gte(b)) + st.throws(() => a.eq(b)) + st.end() + }) +}) + +tape('Add', (t: tape.Test) => { + t.test('should add two same width numbers', (st: tape.Test) => { + const a = new FixedWidthBN(64, 101) + const b = new FixedWidthBN(64, 73) + const c = a.add(b) + st.equal(c.width, 64) + st.equal(c.toNumber(), 174) + // Ensure a and b haven't changed + st.equal(a.toNumber(), 101) + st.equal(b.toNumber(), 73) + st.end() + }) + + t.test('should throw when add overflows', (st: tape.Test) => { + const a = FixedWidthBN.fromString(64, 'fffffffffffffffe') + const b = new FixedWidthBN(64, 2) + st.throws(() => a.add(b)) + st.end() + }) + + t.test('should wrap when addMod overflows', (st: tape.Test) => { + const a = FixedWidthBN.fromString(64, 'fffffffffffffffe') + const b = new FixedWidthBN(64, 3) + const c = a.addMod(b) + st.equal(c.width, 64) + st.equal(c.toNumber(), 1) + st.end() + }) +}) + +tape('Sub', (t: tape.Test) => { + t.test('should sub two same width numbers', (st: tape.Test) => { + const a = new FixedWidthBN(64, 101) + const b = new FixedWidthBN(64, 73) + const c = a.sub(b) + st.equal(c.width, 64) + st.equal(c.toNumber(), 101 - 73) + // Ensure a and b haven't changed + st.equal(a.toNumber(), 101) + st.equal(b.toNumber(), 73) + st.end() + }) + + t.test('should throw sub underflows', (st: tape.Test) => { + const a = new FixedWidthBN(64, 2) + const b = new FixedWidthBN(64, 3) + st.throws(() => a.sub(b)) + st.end() + }) + + t.test('should wrap when subMod underflows', (st: tape.Test) => { + const a = new FixedWidthBN(64, 2) + const b = new FixedWidthBN(64, 3) + const c = a.subMod(b) + st.equal(c.width, 64) + st.equal(c.toString(), 'ffffffffffffffff') + st.end() + }) +}) + +tape('Mul', (t: tape.Test) => { + t.test('should mul two same width numbers', (st: tape.Test) => { + const a = new FixedWidthBN(64, 101) + const b = new FixedWidthBN(64, 73) + const c = a.mul(b) + st.equal(c.width, 64) + st.equal(c.toNumber(), 7373) + // Ensure a and b haven't changed + st.equal(a.toNumber(), 101) + st.equal(b.toNumber(), 73) + st.end() + }) + + t.test('should throw when mul overflows', (st: tape.Test) => { + const a = FixedWidthBN.fromString(64, '8000000000000008') + const b = new FixedWidthBN(64, 2) + st.throws(() => a.mul(b)) + st.end() + }) + + t.test('should wrap when addMod overflows', (st: tape.Test) => { + const a = FixedWidthBN.fromString(64, '8000000000000008') + const b = new FixedWidthBN(64, 2) + const c = a.mulMod(b) + st.equal(c.width, 64) + st.equal(c.toString(), '0000000000000010') + st.end() + }) +}) + +tape('Sqr', (t: tape.Test) => { + t.test('should sqr number', (st: tape.Test) => { + const a = new FixedWidthBN(64, 8) + const c = a.sqr() + st.equal(c.width, 64) + st.equal(c.toNumber(), 64) + st.equal(a.toNumber(), 8) + st.end() + }) + + t.test('should throw when sqr overflows', (st: tape.Test) => { + const a = FixedWidthBN.fromString(64, '100000000') // 2 ** 32 + st.throws(() => a.sqr()) + st.end() + }) + + t.test('should wrap when sqrMod overflows', (st: tape.Test) => { + const a = FixedWidthBN.fromString(64, '100000000') + const c = a.sqrMod() + st.equal(c.width, 64) + st.true(c.isZero()) + st.end() + }) +}) + +tape('Pow', (t: tape.Test) => { + t.test('should pow number', (st: tape.Test) => { + const a = new FixedWidthBN(64, 8) + const b = new FixedWidthBN(64, 4) + const c = a.pow(b) + st.equal(c.width, 64) + st.equal(c.toNumber(), 4096) + st.end() + }) + + t.test('should throw when pow overflows', (st: tape.Test) => { + const a = new FixedWidthBN(64, 2) + const b = new FixedWidthBN(64, 65) + st.throws(() => a.pow(b)) + st.end() + }) + + t.test('should wrap when powMod overflows', (st: tape.Test) => { + const a = new FixedWidthBN(64, 5) + const b = new FixedWidthBN(64, 28) + const c = a.powMod(b) + st.equal(c.width, 64) + st.equal(c.toString(), padHexToLength('4fce5e3e2502611', 64)) + st.end() + }) +}) + +tape('Div', (t: tape.Test) => { + t.test('should div same width numbers', (st: tape.Test) => { + const a = new FixedWidthBN(64, 64) + const b = new FixedWidthBN(64, 4) + const c = a.div(b) + st.equal(c.width, 64) + st.equal(c.toNumber(), 16) + st.end() + }) +}) + +tape('Mod', (t: tape.Test) => { + const a = new FixedWidthBN(8, 17) + const b = new FixedWidthBN(8, 4) + const c = a.mod(b) + t.equal(c.toNumber(), 1) + t.end() +}) + +tape('Or', (t: tape.Test) => { + const a = FixedWidthBN.fromString(8, '11001100', 2) + const b = FixedWidthBN.fromString(8, '10110101', 2) + const c = a.or(b) + t.equal(c.toString(2), '11111101') + t.end() +}) + +tape('And', (t: tape.Test) => { + const a = FixedWidthBN.fromString(8, '11001100', 2) + const b = FixedWidthBN.fromString(8, '10110101', 2) + const c = a.and(b) + t.equal(c.toString(2), '10000100') + t.end() +}) + +tape('Xor', (t: tape.Test) => { + const a = FixedWidthBN.fromString(8, '11001100', 2) + const b = FixedWidthBN.fromString(8, '10110101', 2) + const c = a.xor(b) + t.equal(c.toString(2), '01111001') + t.end() +}) + +tape('Not', (t: tape.Test) => { + const a = FixedWidthBN.fromString(8, '11001100', 2) + const c = a.not() + t.equal(c.toString(2), '00110011') + t.end() +}) + +tape('Shl', (t: tape.Test) => { + const a = FixedWidthBN.fromString(8, '11001100', 2) + const c = a.shl(3) + t.equal(c.toString(2), '01100000') + t.end() +}) + +tape('Shr', (t: tape.Test) => { + const a = FixedWidthBN.fromString(8, '11001100', 2) + const c = a.shr(3) + t.equal(c.toString(2), '00011001') + t.end() +}) + +tape('Test', (t: tape.Test) => { + const a = FixedWidthBN.fromString(8, '11001100', 2) + t.equal(a.test(0), false) + t.equal(a.test(7), true) + t.equal(a.test(2), true) + t.end() +}) + +tape('ToString', (t: tape.Test) => { + const a = FixedWidthBN.fromString(16, '00110011', 2) + t.equal(a.toString(2), '0000000000110011') + t.end() +}) diff --git a/tests/index.js b/tests/index.js deleted file mode 100644 index 46a1d47..0000000 --- a/tests/index.js +++ /dev/null @@ -1,58 +0,0 @@ -const tape = require('tape') -const FixedBN = require('../') - -tape('fix length tests', t => { - let bn = new FixedBN.U256(9879879) - let array = bn.toArray() - t.equals(array.length, 32, 'toArray should produce the correct length') - - t.ok(FixedBN.U256.isFixBN(bn), 'should detect that bn is a fixed bn') - t.ok(FixedBN.U256.isSameWidth(bn), 'should detect that bn is the same length') - - let maxWidth = bn.maxWidth - t.equals(maxWidth, 256, 'should have correct lenght') - - let minWidth = bn.minWidth - t.equals(minWidth, 0, 'should have correct lenght') - - let buffer = bn.toBuffer() - t.equals(buffer.length, 32, 'toBuffer should produce the correct length') - - let fromBN = FixedBN.U256.fromBuffer(buffer) - t.true(fromBN.eq(bn)) - - let arrayLike = bn.toArrayLike(Buffer) - t.equals(arrayLike.length, 32, 'toArrayLike should produce the correct length') - - bn = new FixedBN.U64(9879879) - array = bn.toArray() - t.equals(array.length, 8, 'toArray should produce the correct length') - - buffer = bn.toBuffer() - t.equals(buffer.length, 8, 'toBuffer should produce the correct length') - - arrayLike = bn.toArrayLike(Buffer) - t.equals(arrayLike.length, 8, 'toArrayLike should produce the correct length') - - const fromHex = new FixedBN.U64('0x5555555') - t.equals(fromHex.toString(), '89478485', 'should handle hex strings') - - let threw = false - try { - threw = new FixedBN.U64('0x55555555555555555') - } catch (e) { - threw = true - } - - t.ok(threw, 'should throw error whith invalid length') - - threw = false - try { - threw = new FixedBN.Address('0x55555555555555555') - } catch (e) { - threw = true - } - - t.ok(threw, 'should throw error whith invalid length') - t.end() -}) diff --git a/tests/utils.ts b/tests/utils.ts new file mode 100644 index 0000000..7c9d165 --- /dev/null +++ b/tests/utils.ts @@ -0,0 +1,3 @@ +export const padHexToLength = (hex: string, bitLength: number): string => { + return '0'.repeat(2 * (bitLength / 8 - hex.length / 2)).concat(hex) +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..e7f1cf6 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "@ethereumjs/config-tsc", + "include": ["src/**/*.ts", "src/**/*.json", "tests/*.ts", "tests/*.json"] +} diff --git a/tsconfig.prod.json b/tsconfig.prod.json new file mode 100644 index 0000000..854acb1 --- /dev/null +++ b/tsconfig.prod.json @@ -0,0 +1,7 @@ +{ + "extends": "@ethereumjs/config-tsc", + "compilerOptions": { + "outDir": "./dist" + }, + "include": ["src/**/*.ts", "src/**/*.json"] +} diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..2ba21c4 --- /dev/null +++ b/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": "@ethereumjs/config-tslint" +}