Skip to content

Commit

Permalink
feat: new APIs (getPrivateKeyFromEthSignature, privateToStarkKey) (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
dan-ziv authored Mar 30, 2022
1 parent 5cb7ab8 commit bf4066c
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 166 deletions.
3 changes: 1 addition & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ All notable changes to this project will be documented in this file. See [standa

### 0.0.1 (2022-03-08)


### Features

* init project ([9759ffa](https://github.com/starkware-libs/starkware-crypto-utils/commit/9759ffac52538345524c90a784e653c95d8899f5))
- init project ([9759ffa](https://github.com/starkware-libs/starkware-crypto-utils/commit/9759ffac52538345524c90a784e653c95d8899f5))
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ const starkwareCrypto = require('@starkware-industries/starkware-crypto-utils');

keyDerivation: {
StarkExEc: ec.n, // Data.
getPrivateKeyFromEthSignature,
privateToStarkKey,
getKeyPairFromPath,
getAccountPath,
grindKey // Function.
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,10 @@
},
"devDependencies": {
"chai": "^4.3.6",
"eslint": "^8.8.0",
"eslint": "^8.11.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"mocha": "^8.4.0",
"mocha": "^9.2.2",
"prettier": "^2.5.1",
"standard-version": "^9.3.2"
}
Expand Down
3 changes: 2 additions & 1 deletion src/config/keys_precomputed.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@
"0x4615f94598cd756ad1a551d7e57fd725916adfd0054eb773ceb482eef87d0b2": "0x1ee5b8d612102a2408cde59ce52a6498d2e38fe8789bb26d400dea310684ec9",
"0x6ade54b7debd7ca1d4e8e932f9545f8fa4024d73be1efcc86df86367fc333f8": "0x37de3bf52412b2fb9b0030d232ca9dd921cd8f71fd67975cdc62546826e121",
"0x618e7467dd24c2a3449c4df640439c12cdd0f8ea779afcee6e252b2cf494354": "0x71c2b578c432f2d305d3808bb645ecc46dd670cb43d4f4a076f75ccbff74fbc",
"0x7eae185e1f41ec76d214d763f0592f194933622a9dd5f3d52d0209f71619c1a": "0x2b0160052e70176e5b0ff2a6eff90896ae07b732fc27219e36e077735abd57e"
"0x7eae185e1f41ec76d214d763f0592f194933622a9dd5f3d52d0209f71619c1a": "0x2b0160052e70176e5b0ff2a6eff90896ae07b732fc27219e36e077735abd57e",
"0x178047D3869489C055D7EA54C014FFB834A069C9595186ABE04EA4D1223A03F": "0x1895a6a77ae14e7987b9cb51329a5adfb17bd8e7c638f92d6892d76e51cebcf"
}
41 changes: 40 additions & 1 deletion src/js/key_derivation.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ const encUtils = require('enc-utils');
const BN = require('bn.js');
const hash = require('hash.js');
const {ec} = require('./signature.js');
const assert = require('assert');

const ETH_SIGNATURE_LENGTH = 130;
const STARK_PRIVATE_KEY_LENGTH = 63;

/*
Returns an integer from a given section of bits out of a hex string.
Expand All @@ -34,6 +38,38 @@ function getIntFromBits(hex, start, end = undefined) {
return int;
}

/*
Returns true if the given string is a hex string of length hexLength, and false otherwise.
*/
function isHexOfLength(hex, hexLength) {
const regex = new RegExp('^[0-9a-fA-F]{' + hexLength + '}$');
return regex.test(hex);
}

/*
Returns a private stark key based on a given Eth signature.
The given signature should be a 130 character hex string produced by the user signing a
predetermined message in order to guarantee getting the same private key each time it is invoked.
*/
function getPrivateKeyFromEthSignature(ethSignature) {
const ethSignatureFixed = ethSignature.replace(/^0x/, '');
assert(isHexOfLength(ethSignatureFixed, ETH_SIGNATURE_LENGTH));
const r = ethSignatureFixed.substring(0, 64);
return grindKey(r, ec.n);
}

/*
Returns a public stark key given the private key.
The private key should be a random hex string of length up to 63 characters.
*/
function privateToStarkKey(privateKey) {
const privateKeyFixed = privateKey.replace(/^0x/, '');
assert(privateKeyFixed.length <= STARK_PRIVATE_KEY_LENGTH);
assert(isHexOfLength(privateKeyFixed, privateKeyFixed.length));
const keyPair = ec.keyFromPrivate(privateKeyFixed, 'hex');
return keyPair.getPublic().getX().toJSON();
}

/*
Derives key-pair from given mnemonic string and path.
mnemonic should be a sentence comprised of 12 words with single spaces between them.
Expand Down Expand Up @@ -117,7 +153,10 @@ function hashKeyWithIndex(key, index) {

module.exports = {
StarkExEc: ec.n, // Data.
getPrivateKeyFromEthSignature,
privateToStarkKey,
getKeyPairFromPath,
getAccountPath,
grindKey // Function.
grindKey
// Function.
};
23 changes: 23 additions & 0 deletions test/js/key_derivation.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ const {
StarkExEc,
getKeyPairFromPath,
getAccountPath,
privateToStarkKey,
getPrivateKeyFromEthSignature,
grindKey
} = require(`${SRC_DIR_PATH}/key_derivation`);
const precomputedKeys = require(`${CONFIG_DIR_PATH}/keys_precomputed.json`);

const layer = 'starkex';
const application = 'starkdeployement';
Expand Down Expand Up @@ -48,3 +51,23 @@ describe('Key grinding', () => {
);
});
});

describe('Private to stark key', () => {
it('should derive public stark key from private correctly', () => {
Object.entries(precomputedKeys).forEach(([privKey, expectedPubKey]) => {
const pubKey = '0x' + privateToStarkKey(privKey);
expect(pubKey).to.equal(expectedPubKey);
});
});
});

describe('Private stark key from eth signature', () => {
it('should derive private stark key from eth signature correctly', () => {
const ethSignature =
'0x21fbf0696d5e0aa2ef41a2b4ffb623bcaf070461d61cf7251c74161f82fec3a43' +
'70854bc0a34b3ab487c1bc021cd318c734c51ae29374f2beb0e6f2dd49b4bf41c';
expect(getPrivateKeyFromEthSignature(ethSignature)).to.equal(
'766f11e90cd7c7b43085b56da35c781f8c067ac0d578eabdceebc4886435bda'
);
});
});
16 changes: 0 additions & 16 deletions test/js/signature.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/* eslint-disable no-unused-expressions */
const starkwareCrypto = require(`${SRC_DIR_PATH}/signature.js`);
const precomputedKeys = require(`${CONFIG_DIR_PATH}/keys_precomputed.json`);
const rfc6979TestData = require('../config/rfc6979_signature_test_vector.json');
const testData = require('../config/signature_test_data.json');
const BN = require('bn.js');
Expand All @@ -23,21 +22,6 @@ function randomString(characters, length) {
return result;
}

describe('Key computation', () => {
it('should derive public key correctly', () => {
for (const privKey in precomputedKeys) {
if ({}.hasOwnProperty.call(precomputedKeys, privKey)) {
// Drop the '0x' prefix.
const fixedPrivKey = privKey.substring(2);
const keyPair = starkwareCrypto.ec.keyFromPrivate(fixedPrivKey, 'hex');
const pubKey = '0x' + keyPair.getPublic().getX().toString('hex');
const expectedPubKey = precomputedKeys[privKey];
expect(expectedPubKey).to.equal(pubKey);
}
}
});
});

describe('Verify', () => {
// Generate BN of 1.
const oneBn = new BN('1', 16);
Expand Down
Loading

0 comments on commit bf4066c

Please sign in to comment.