This repository has been archived by the owner on May 16, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* porting legacy stark grind methods to core sdk * DX-2184: Passing tests for GrindKey legacy * DX-2184: Added tests to charecterize the legacy grind key implementation * Dx 2184 gk3 (#342) * Dx-2184: Rebasing the changes off gring-key-revert branch * DX-2184: First pass of Backwards Compatible logic Co-authored-by: Nik <[email protected]> * DX-2184: Added Tests for Backwards compatible key gen Co-authored-by: Nik <[email protected]> * DX-2184: Removed todo Co-authored-by: Nik <[email protected]> * DX-2184: ethAddress is non-optional now * DX-2184: Using 2.0.0 grindKey as the default version Co-authored-by: Carl Menezes <[email protected]> Co-authored-by: Nik <[email protected]> * DX-2184: Added Changelog Co-authored-by: Carl Menezes <[email protected]> Co-authored-by: Nik <[email protected]> * DX-2184: Added tests for legacy imx-sdk-js version * PR fix --------- Co-authored-by: Carl Menezes <[email protected]> Co-authored-by: Nik <[email protected]> --------- Co-authored-by: Chris James <[email protected]> Co-authored-by: Carl Menezes <[email protected]> Co-authored-by: Nik <[email protected]>
- Loading branch information
1 parent
aad87d4
commit e688709
Showing
9 changed files
with
2,620 additions
and
82 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import BN from 'bn.js'; | ||
import { curves, ec as Ec } from 'elliptic'; | ||
import hashJS from 'hash.js'; | ||
|
||
import { constantPointsHex } from './points'; | ||
import { Instruction, InstructionWithFee } from './types'; | ||
|
||
const DEFAULT_ACCOUNT_MAPPING_KEY = 'STARKWARE_ACCOUNT_MAPPING'; | ||
const DEFAULT_SIGNATURE_MESSAGE = | ||
'Only sign this request if you’ve initiated an action with Immutable X.'; | ||
|
||
const DEFAULT_ACCOUNT_LAYER = 'starkex'; | ||
const DEFAULT_ACCOUNT_APPLICATION = 'immutablex'; | ||
const DEFAULT_ACCOUNT_INDEX = '1'; | ||
|
||
const NFT_ASSET_ID_PREFIX = 'NFT:'; | ||
const MINTABLE_ASSET_ID_PREFIX = 'MINTABLE:'; | ||
|
||
const prime = new BN( | ||
'800000000000011000000000000000000000000000000000000000000000001', | ||
16, | ||
); | ||
const order = new BN( | ||
'08000000 00000010 ffffffff ffffffff b781126d cae7b232 1e66a241 adc64d2f', | ||
16, | ||
); | ||
|
||
const starkEc = new Ec( | ||
new curves.PresetCurve({ | ||
type: 'short', | ||
prime: null, | ||
p: prime as any, | ||
a: '00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001', | ||
b: '06f21413 efbe40de 150e596d 72f7a8c5 609ad26c 15c915c1 f4cdfcb9 9cee9e89', | ||
n: order as any, | ||
hash: hashJS.sha256, | ||
gRed: false, | ||
g: constantPointsHex[1], | ||
}), | ||
); | ||
|
||
const constantPoints = constantPointsHex.map((coords: string[]) => | ||
starkEc.curve.point(new BN(coords[0], 16), new BN(coords[1], 16)), | ||
); | ||
const shiftPoint = constantPoints[0]; | ||
|
||
// Instruction type mapping encoded in BigNumber | ||
// see https://docs.starkware.co/starkex-v3/starkex-deep-dive/message-encodings/signatures | ||
const instructionEncodingMap: { | ||
[instruction in Instruction | InstructionWithFee]: BN; | ||
} = { | ||
order: new BN('0'), | ||
transfer: new BN('1'), | ||
orderWithFee: new BN('3'), | ||
transferWithFee: new BN('4'), | ||
registerUser: new BN('1000'), | ||
deposit: new BN('1001'), | ||
withdraw: new BN('1002'), | ||
cancelOrder: new BN('1003'), | ||
}; | ||
|
||
const ZERO_BN = new BN('0'); | ||
const ONE_BN = new BN('1'); | ||
const TWO_POW_22_BN = new BN('400000', 16); | ||
const TWO_POW_31_BN = new BN('80000000', 16); | ||
const TWO_POW_63_BN = new BN('8000000000000000', 16); | ||
// Equals 2**251 + 17 * 2**192 + 1. | ||
const PRIME_BN = new BN( | ||
'800000000000011000000000000000000000000000000000000000000000001', | ||
16, | ||
); | ||
// Equals 2**251. This value limits msgHash and the signature parts. | ||
const MAX_ECDSA_BN = new BN( | ||
'800000000000000000000000000000000000000000000000000000000000000', | ||
16, | ||
); | ||
|
||
const MISSING_HEX_PREFIX = 'Hex strings expected to be prefixed with 0x.'; | ||
|
||
const ORDER = new BN( | ||
'08000000 00000010 ffffffff ffffffff b781126d cae7b232 1e66a241 adc64d2f', | ||
16, | ||
); | ||
const SECP_ORDER = new BN( | ||
'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141', | ||
16, | ||
); | ||
|
||
export { | ||
constantPoints, | ||
DEFAULT_ACCOUNT_APPLICATION, | ||
DEFAULT_ACCOUNT_INDEX, | ||
DEFAULT_ACCOUNT_LAYER, | ||
DEFAULT_ACCOUNT_MAPPING_KEY, | ||
DEFAULT_SIGNATURE_MESSAGE, | ||
instructionEncodingMap, | ||
MAX_ECDSA_BN, | ||
MINTABLE_ASSET_ID_PREFIX, | ||
MISSING_HEX_PREFIX, | ||
NFT_ASSET_ID_PREFIX, | ||
ONE_BN, | ||
ORDER, | ||
prime, | ||
PRIME_BN, | ||
SECP_ORDER, | ||
shiftPoint, | ||
starkEc, | ||
TWO_POW_22_BN, | ||
TWO_POW_31_BN, | ||
TWO_POW_63_BN, | ||
ZERO_BN, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
/* eslint-disable no-param-reassign */ | ||
/* eslint-disable no-plusplus */ | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import assert from 'assert'; | ||
import BN from 'bn.js'; | ||
import { ec } from 'elliptic'; | ||
import * as encUtils from 'enc-utils'; | ||
import { hdkey } from 'ethereumjs-wallet'; | ||
import hashJS from 'hash.js'; | ||
|
||
import { | ||
MISSING_HEX_PREFIX, | ||
ORDER, | ||
PRIME_BN, | ||
SECP_ORDER, | ||
starkEc, | ||
ZERO_BN, | ||
} from './constants'; | ||
|
||
export function isHexPrefixed(str: string): boolean { | ||
return str.substring(0, 2) === '0x'; | ||
} | ||
|
||
export function checkHexValue(hex: string): void { | ||
assert(isHexPrefixed(hex), MISSING_HEX_PREFIX); | ||
const hexBn = new BN(encUtils.removeHexPrefix(hex), 16); | ||
assert(hexBn.gte(ZERO_BN)); | ||
assert(hexBn.lt(PRIME_BN)); | ||
} | ||
|
||
export function getIntFromBits( | ||
hex: string, | ||
start: number, | ||
end: number | undefined = undefined, | ||
): number { | ||
const bin = encUtils.hexToBinary(hex); | ||
const bits = bin.slice(start, end); | ||
const int = encUtils.binaryToNumber(bits); | ||
return int; | ||
} | ||
|
||
export function getAccountPath( | ||
layer: string, | ||
application: string, | ||
ethereumAddress: string, | ||
index: string, | ||
): string { | ||
const layerHash = hashJS.sha256().update(layer).digest('hex'); | ||
const applicationHash = hashJS.sha256().update(application).digest('hex'); | ||
const layerInt = getIntFromBits(layerHash, -31); | ||
const applicationInt = getIntFromBits(applicationHash, -31); | ||
const ethAddressInt1 = getIntFromBits(ethereumAddress, -31); | ||
const ethAddressInt2 = getIntFromBits(ethereumAddress, -62, -31); | ||
return `m/2645'/${layerInt}'/${applicationInt}'/${ethAddressInt1}'/${ethAddressInt2}'/${index}`; | ||
} | ||
|
||
export function hashKeyWithIndex(key: string, index: number): BN { | ||
return new BN( | ||
hashJS | ||
.sha256() | ||
.update( | ||
encUtils.hexToBuffer( | ||
encUtils.removeHexPrefix(key) + | ||
encUtils.sanitizeBytes(encUtils.numberToHex(index), 2), | ||
), | ||
) | ||
.digest('hex'), | ||
16, | ||
); | ||
} | ||
|
||
export function grindKey(privateKey: string): string { | ||
let i = 0; | ||
let key: BN = hashKeyWithIndex(privateKey, i); | ||
|
||
while (!key.lt(SECP_ORDER.sub(SECP_ORDER.mod(ORDER)))) { | ||
key = hashKeyWithIndex(key.toString(16), i); | ||
i = i++; | ||
} | ||
return key.mod(ORDER).toString('hex'); | ||
} | ||
|
||
export function getKeyPair(privateKey: string): ec.KeyPair { | ||
return starkEc.keyFromPrivate(privateKey, 'hex'); | ||
} | ||
|
||
export function getPrivateKeyFromPath(seed: string, path: string): string { | ||
return hdkey | ||
.fromMasterSeed(Buffer.from(seed.slice(2), 'hex')) // assuming seed is '0x...' | ||
.derivePath(path) | ||
.getWallet() | ||
.getPrivateKeyString(); | ||
} | ||
|
||
export function getKeyPairFromPath(seed: string, path: string): ec.KeyPair { | ||
assert(isHexPrefixed(seed), MISSING_HEX_PREFIX); | ||
const privateKey = getPrivateKeyFromPath(seed, path); | ||
return getKeyPair(grindKey(privateKey)); | ||
} | ||
|
||
export function getPublic(keyPair: ec.KeyPair, compressed = false): string { | ||
return keyPair.getPublic(compressed, 'hex'); | ||
} | ||
|
||
export function getStarkPublicKey(keyPair: ec.KeyPair): string { | ||
return getPublic(keyPair, true); | ||
} | ||
|
||
export function getKeyPairFromPublicKey(publicKey: string): ec.KeyPair { | ||
return starkEc.keyFromPublic(encUtils.hexToArray(publicKey)); | ||
} | ||
|
||
export function getKeyPairFromPrivateKey(privateKey: string): ec.KeyPair { | ||
return starkEc.keyFromPrivate(privateKey, 'hex'); | ||
} | ||
|
||
export function getXCoordinate(publicKey: string): string { | ||
const keyPair = getKeyPairFromPublicKey(publicKey); | ||
return encUtils.sanitizeBytes((keyPair as any).pub.getX().toString(16), 2); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './constants'; | ||
export * from './crypto'; |
Oops, something went wrong.