Skip to content

Commit 04479e4

Browse files
authored
Merge pull request #78 from seanjameshan/feature/utils-shortstring-and-uint256
feat(utils): support shortstring and uint256
2 parents aa7ae82 + e5bdb18 commit 04479e4

File tree

7 files changed

+117
-6
lines changed

7 files changed

+117
-6
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { decodeShortString, encodeShortString } from '../../src/utils/shortString';
2+
3+
describe('shortString', () => {
4+
test('should convert string to number', () => {
5+
expect(encodeShortString('hello')).toMatchInlineSnapshot(`"0x68656c6c6f"`);
6+
});
7+
test('should convert number to string', () => {
8+
expect(decodeShortString('0x68656c6c6f')).toMatchInlineSnapshot(`"hello"`);
9+
});
10+
test('should throw if string is too long', () => {
11+
expect(() =>
12+
encodeShortString('hello world hello world hello world hello world hello world hello world')
13+
).toThrowErrorMatchingInlineSnapshot(
14+
`"hello world hello world hello world hello world hello world hello world is too long"`
15+
);
16+
});
17+
test('should throw if string contains non ascii chars', () => {
18+
expect(() => encodeShortString('hello\uD83D\uDE00')).toThrowErrorMatchingInlineSnapshot(
19+
`"hello😀 is not an ASCII string"`
20+
);
21+
});
22+
});

__tests__/utils/uint256.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { ONE } from '../../src/constants';
2+
import { toBN } from '../../src/utils/number';
3+
import { UINT_128_MAX, UINT_256_MAX, bnToUint256, uint256ToBN } from '../../src/utils/uint256';
4+
5+
describe('cairo uint256', () => {
6+
test('should convert 0 from BN to uint256 struct', () => {
7+
const uint256 = bnToUint256('0');
8+
expect(uint256).toMatchInlineSnapshot(`
9+
Object {
10+
"high": "0x0",
11+
"low": "0x0",
12+
}
13+
`);
14+
});
15+
test('should convert 0 from uint256 to BN', () => {
16+
expect(uint256ToBN({ low: '0x0', high: '0x0' }).toString()).toMatchInlineSnapshot(`"0"`);
17+
});
18+
test('should convert BN over 2^128 to uint256 struct', () => {
19+
const uint256 = bnToUint256(UINT_128_MAX.add(ONE));
20+
expect(uint256).toMatchInlineSnapshot(`
21+
Object {
22+
"high": "0x1",
23+
"low": "0x0",
24+
}
25+
`);
26+
});
27+
test('should throw if BN over uint256 range', () => {
28+
expect(() => bnToUint256(UINT_256_MAX.add(toBN(1)))).toThrowErrorMatchingInlineSnapshot(
29+
`"Number is too large"`
30+
);
31+
});
32+
});

src/constants.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
import BN from 'bn.js';
2-
31
import { toBN } from './utils/number';
42

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

7-
export const ZERO: BN = toBN(0);
8-
export const ONE: BN = toBN(1);
9-
export const TWO: BN = toBN(2);
10-
export const MASK_250: BN = TWO.pow(toBN(250)).sub(ONE); // 2 ** 250 - 1
5+
export const ZERO = toBN(0);
6+
export const ONE = toBN(1);
7+
export const TWO = toBN(2);
8+
export const MASK_250 = TWO.pow(toBN(250)).sub(ONE); // 2 ** 250 - 1
119

1210
/**
1311
* 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

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,5 @@ export * as json from './utils/json';
1616
export * as number from './utils/number';
1717
export * as stark from './utils/stark';
1818
export * as ec from './utils/ellipticCurve';
19+
export * as uint256 from './utils/uint256';
20+
export * as shortString from './utils/shortString';

src/utils/shortString.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { addHexPrefix, removeHexPrefix } from './encode';
2+
3+
export function isASCII(str: string) {
4+
// eslint-disable-next-line no-control-regex
5+
return /^[\x00-\x7F]*$/.test(str);
6+
}
7+
8+
// function to check if string has less or equal 31 characters
9+
export function isShortString(str: string) {
10+
return str.length <= 31;
11+
}
12+
13+
export function encodeShortString(str: string) {
14+
if (!isASCII(str)) throw new Error(`${str} is not an ASCII string`);
15+
if (!isShortString(str)) throw new Error(`${str} is too long`);
16+
return addHexPrefix(str.replace(/./g, (char) => char.charCodeAt(0).toString(16)));
17+
}
18+
19+
export function decodeShortString(str: string) {
20+
return removeHexPrefix(str).replace(/.{2}/g, (hex) => String.fromCharCode(parseInt(hex, 16)));
21+
}

src/utils/stark.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,7 @@ export function formatSignature(sig?: [BigNumberish, BigNumberish]): [string, st
4949
return [];
5050
}
5151
}
52+
53+
export function compileStructToCalldata<S extends { [k: string]: string }>(struct: S): string[] {
54+
return Object.values(struct);
55+
}

src/utils/uint256.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { addHexPrefix } from './encode';
2+
import { BigNumberish, toBN } from './number';
3+
4+
// Represents an integer in the range [0, 2^256).
5+
export interface Uint256 {
6+
// The low 128 bits of the value.
7+
low: BigNumberish;
8+
// The high 128 bits of the value.
9+
high: BigNumberish;
10+
}
11+
12+
// function to convert Uint256 to BN
13+
export function uint256ToBN(uint256: Uint256) {
14+
return toBN(uint256.high).shln(128).add(toBN(uint256.low));
15+
}
16+
17+
export const UINT_128_MAX = toBN(1).shln(128).sub(toBN(1));
18+
export const UINT_256_MAX = toBN(1).shln(256).sub(toBN(1));
19+
// function to check if BN is smaller or equal 2**256-1
20+
export function isUint256(bn: BigNumberish): boolean {
21+
return toBN(bn).lte(UINT_256_MAX);
22+
}
23+
24+
// function to convert BN to Uint256
25+
export function bnToUint256(bignumber: BigNumberish): Uint256 {
26+
const bn = toBN(bignumber);
27+
if (!isUint256(bn)) throw new Error('Number is too large');
28+
return {
29+
low: addHexPrefix(bn.maskn(128).toString(16)),
30+
high: addHexPrefix(bn.shrn(128).toString(16)),
31+
};
32+
}

0 commit comments

Comments
 (0)