Skip to content

Commit

Permalink
feat(utils): support shortstring and uint256
Browse files Browse the repository at this point in the history
  • Loading branch information
janek26 committed Dec 1, 2021
1 parent aa7ae82 commit f7ff057
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 6 deletions.
22 changes: 22 additions & 0 deletions __tests__/utils/shortString.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { decodeShortString, encodeShortString } from '../../src/utils/shortString';

describe('shortString', () => {
test('should convert string to number', () => {
expect(encodeShortString('hello')).toMatchInlineSnapshot(`"0x68656c6c6f"`);
});
test('should convert number to string', () => {
expect(decodeShortString('0x68656c6c6f')).toMatchInlineSnapshot(`"hello"`);
});
test('should throw if string is too long', () => {
expect(() =>
encodeShortString('hello world hello world hello world hello world hello world hello world')
).toThrowErrorMatchingInlineSnapshot(
`"hello world hello world hello world hello world hello world hello world is too long"`
);
});
test('should throw if string contains non ascii chars', () => {
expect(() => encodeShortString('hello\uD83D\uDE00')).toThrowErrorMatchingInlineSnapshot(
`"hello😀 is not an ASCII string"`
);
});
});
32 changes: 32 additions & 0 deletions __tests__/utils/uint256.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { ONE } from '../../src/constants';
import { toBN } from '../../src/utils/number';
import { UINT_128_MAX, UINT_256_MAX, bnToUint256, uint256ToBN } from '../../src/utils/uint256';

describe('cairo uint256', () => {
test('should convert 0 from BN to uint256 struct', () => {
const uint256 = bnToUint256('0');
expect(uint256).toMatchInlineSnapshot(`
Object {
"high": "0x0",
"low": "0x0",
}
`);
});
test('should convert 0 from uint256 to BN', () => {
expect(uint256ToBN({ low: '0x0', high: '0x0' }).toString()).toMatchInlineSnapshot(`"0"`);
});
test('should convert BN over 2^128 to uint256 struct', () => {
const uint256 = bnToUint256(UINT_128_MAX.add(ONE));
expect(uint256).toMatchInlineSnapshot(`
Object {
"high": "0x1",
"low": "0x0",
}
`);
});
test('should throw if BN over uint256 range', () => {
expect(() => bnToUint256(UINT_256_MAX.add(toBN(1)))).toThrowErrorMatchingInlineSnapshot(
`"Number is too large"`
);
});
});
10 changes: 4 additions & 6 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import BN from 'bn.js';

import { toBN } from './utils/number';

export { IS_BROWSER } from './utils/encode';

export const ZERO: BN = toBN(0);
export const ONE: BN = toBN(1);
export const TWO: BN = toBN(2);
export const MASK_250: BN = TWO.pow(toBN(250)).sub(ONE); // 2 ** 250 - 1
export const ZERO = toBN(0);
export const ONE = toBN(1);
export const TWO = toBN(2);
export const MASK_250 = TWO.pow(toBN(250)).sub(ONE); // 2 ** 250 - 1

/**
* The following is taken from https://github.com/starkware-libs/starkex-resources/blob/master/crypto/starkware/crypto/signature/pedersen_params.json but converted to hex, because JS is very bad handling big integers by default
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ export * as json from './utils/json';
export * as number from './utils/number';
export * as stark from './utils/stark';
export * as ec from './utils/ellipticCurve';
export * as uint256 from './utils/uint256';
export * as shortString from './utils/shortString';
21 changes: 21 additions & 0 deletions src/utils/shortString.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { addHexPrefix, removeHexPrefix } from './encode';

export function isASCII(str: string) {
// eslint-disable-next-line no-control-regex
return /^[\x00-\x7F]*$/.test(str);
}

// function to check if string has less or equal 31 characters
export function isShortString(str: string) {
return str.length <= 31;
}

export function encodeShortString(str: string) {
if (!isASCII(str)) throw new Error(`${str} is not an ASCII string`);
if (!isShortString(str)) throw new Error(`${str} is too long`);
return addHexPrefix(str.replace(/./g, (char) => char.charCodeAt(0).toString(16)));
}

export function decodeShortString(str: string) {
return removeHexPrefix(str).replace(/.{2}/g, (hex) => String.fromCharCode(parseInt(hex, 16)));
}
32 changes: 32 additions & 0 deletions src/utils/uint256.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { addHexPrefix } from './encode';
import { BigNumberish, toBN } from './number';

// Represents an integer in the range [0, 2^256).
export interface Uint256 {
// The low 128 bits of the value.
low: BigNumberish;
// The high 128 bits of the value.
high: BigNumberish;
}

// function to convert Uint256 to BN
export function uint256ToBN(uint256: Uint256) {
return toBN(uint256.high).shln(128).add(toBN(uint256.low));
}

export const UINT_128_MAX = toBN(1).shln(128).sub(toBN(1));
export const UINT_256_MAX = toBN(1).shln(256).sub(toBN(1));
// function to check if BN is smaller or equal 2**256-1
export function isUint256(bn: BigNumberish): boolean {
return toBN(bn).lte(UINT_256_MAX);
}

// function to convert BN to Uint256
export function bnToUint256(bignumber: BigNumberish): Uint256 {
const bn = toBN(bignumber);
if (!isUint256(bn)) throw new Error('Number is too large');
return {
low: addHexPrefix(bn.maskn(128).toString(16)),
high: addHexPrefix(bn.shrn(128).toString(16)),
};
}

0 comments on commit f7ff057

Please sign in to comment.