Skip to content

Commit

Permalink
Merge pull request #58 from nash-io/ts/neo3-address-generation
Browse files Browse the repository at this point in the history
add support for generating neo3 address from neo private key
  • Loading branch information
localhuman authored Jul 15, 2022
2 parents 760f9d1 + 66cc9d7 commit d61295d
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 63 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

### [4.8.1](https://github.com/nash-io/nash-protocol/compare/v4.7.2...v4.8.1) (2022-07-15)

### [4.7.2](https://github.com/nash-io/nash-protocol/compare/v4.7.0...v4.7.2) (2022-02-08)

## [4.7.0](https://github.com/nash-io/nash-protocol/compare/v4.5.12...v4.7.0) (2022-01-13)
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@neon-exchange/nash-protocol",
"version": "4.7.2",
"version": "4.8.1",
"description": "TypeScript implementation of Nash crypto routines",
"main": "build/main/index.js",
"typings": "build/main/index.d.ts",
Expand Down
16 changes: 15 additions & 1 deletion src/__tests__/testVectors.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,20 @@
"address": "ANwZ2RFRKrASBvZifGgjqqJNUbfJUW6gbn"
}
],
"neo3": [
{
"index": 0,
"privateKey": "491aac461bd2e0eb02ffe6cdb534a03617e8811764e4eea042f24231ba99b76f",
"publicKey": "0208035f32c5d0e59f71c55b1e060f6d504c004222c25670ff2b788d76a84af2f2",
"address": "NVM1JPRvibsqvQBwmSFQeW7DgfYmHV9WZ9"
},
{
"index": 1,
"privateKey": "b478febf68d16aa3fa696d684589b9a706f04065407897319a4a4a33aa2cd1e5",
"publicKey": "03a41d39a4209e18eb79245ea368674edf335a4ebeb8ed344b87d3ccaf3a2c730e",
"address": "NQGUB6AxfmYWowUQVXYa46fadqbsh19MYn"
}
],
"ltc": {
"MainNet": {
"address": "MCPi7QVw4DGJMapjUNtArnMHCsRQpHPo1e",
Expand Down Expand Up @@ -132,4 +146,4 @@
}
}
}
]
]
48 changes: 20 additions & 28 deletions src/generateWallet/generateWallet.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { generateNashPayloadSigningKey, generateWallet, CoinType } from './generateWallet'
import _ from 'lodash'
import testVectors from '../__tests__/testVectors.json'
import { Blockchain } from '../types'
// import { cryptoWaitReady } from '@polkadot/util-crypto'

test('generates deterministic BIP44 ETH keys', async () => {
Expand Down Expand Up @@ -31,6 +32,24 @@ test('generates deterministic BIP44 NEO keys', async () => {
}
})


test('generates deterministic BIP44 NEO3 keys', async () => {

for (const vector of testVectors) {
const masterSeed = Buffer.from(vector.masterSeed, 'hex')

for (const wallet of vector.wallets.neo3) {
const genWallet = generateWallet(masterSeed, CoinType.NEO, wallet.index, '', Blockchain.NEO3)
expect(genWallet.address).toBe(wallet.address)
expect(genWallet.publicKey).toBe(wallet.publicKey)
expect(genWallet.privateKey).toBe(wallet.privateKey)
expect(genWallet.index).toBe(wallet.index)
}
}

})


test('generates deterministic BIP44 BTC keys', async () => {
for (const vector of testVectors) {
const masterSeed = Buffer.from(vector.masterSeed, 'hex')
Expand Down Expand Up @@ -105,34 +124,7 @@ test('generates deterministic BIP44 bitcoincash keys', async () => {
}
})

// test('generates deterministic BIP44 dot keys', async () => {
// await cryptoWaitReady()

// for (const vector of testVectors) {
// const masterSeed = Buffer.from(vector.masterSeed, 'hex')
// const wallet = vector.wallets.dot.MainNet

// const genWallet = generateWallet(masterSeed, CoinType.DOT, wallet.index, 'MainNet')
// expect(genWallet.address).toBe(wallet.address)
// expect(genWallet.publicKey).toBe(wallet.publicKey)
// expect(genWallet.privateKey).toBe(wallet.privateKey)
// expect(genWallet.index).toBe(wallet.index)
// }
// })

// test('generates deterministic BIP44 erd keys', async () => {
// await cryptoWaitReady()

// for (const vector of testVectors) {
// const masterSeed = Buffer.from(vector.masterSeed, 'hex')
// const wallet = vector.wallets.erd.MainNet
// const genWallet = generateWallet(masterSeed, CoinType.ERD, wallet.index, 'MainNet')
// expect(genWallet.address).toBe(wallet.address)
// expect(genWallet.publicKey).toBe(wallet.publicKey)
// expect(genWallet.privateKey).toBe(wallet.privateKey)
// expect(genWallet.index).toBe(wallet.index)
// }
// })


test('generates deterministic payload signing key', async () => {
for (const vector of testVectors) {
Expand Down
48 changes: 17 additions & 31 deletions src/generateWallet/generateWallet.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as bip32 from 'bip32'
import { Wallet } from '../types'
import { Blockchain, Wallet } from '../types'
import { reverseHex } from '../utils/getNEOScriptHash/getNEOScripthash'
import * as EthUtil from 'ethereumjs-util'
import * as Bitcoin from 'bitcoinjs-lib'
Expand Down Expand Up @@ -33,21 +33,18 @@ export enum CoinType {

const NON_SEGWIT = [CoinType.BCH, CoinType.DOGE]

// interface DotKeyPair {
// publicKey: Uint8Array
// address: string
// }

/**
* Creates a wallet for a given token via the
* [BIP-44 protocol]((https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki).
*
* Requires the user's master seed.
*/
export function generateWallet(masterSeed: Buffer, coinType: CoinType, index: number, net?: string): Wallet {
export function generateWallet(masterSeed: Buffer, coinType: CoinType, index: number, net?: string, blockchain?: Blockchain): Wallet {
const key = derivePath(masterSeed, bip44Purpose, coinType, 0, 0)
const derivedChainKey = deriveIndex(key, index)

return generateWalletForCoinType(derivedChainKey, coinType, index, net)
return generateWalletForCoinType(derivedChainKey, coinType, index, net, blockchain)
}

/**
Expand Down Expand Up @@ -128,7 +125,10 @@ export function neoGetPublicKeyFromPrivateKey(privateKey: string, encode: boolea
}
}

const getVerificationScriptFromPublicKey = (publicKey: string): string => {
const getVerificationScriptFromPublicKey = (publicKey: string, blockchain?: Blockchain): string => {
if (blockchain && blockchain === Blockchain.NEO3) {
return '0c21' + publicKey + '4156e7b327'
}
return '21' + publicKey + 'ac'
}

Expand All @@ -153,26 +153,29 @@ export function hash256(hex: string): string {
}

const ADDR_VERSION = '17'
const NEO3_ADDR_VERSION = '35'

export const getAddressFromScriptHash = (scriptHash: string): string => {
export const getAddressFromScriptHash = (scriptHash: string, addressVersion: string): string => {
const scriptHashReversed = reverseHex(scriptHash)
const shaChecksum = hash256(ADDR_VERSION + scriptHashReversed).substr(0, 8)
return base58.encode(Buffer.from(ADDR_VERSION + scriptHashReversed + shaChecksum, 'hex'))
const shaChecksum = hash256(addressVersion + scriptHashReversed).substr(0, 8)
return base58.encode(Buffer.from(addressVersion + scriptHashReversed + shaChecksum, 'hex'))
}


// NOTE: We can split this out later when there are more wallets needs to be derived.
function generateWalletForCoinType(key: bip32.BIP32Interface, coinType: CoinType, index: number, net?: string): Wallet {
function generateWalletForCoinType(key: bip32.BIP32Interface, coinType: CoinType, index: number, net?: string, blockchain?: Blockchain): Wallet {
if (key.privateKey === undefined) {
throw new Error('private key not properly derived')
}
switch (coinType) {
case CoinType.NEO:
const neoPrivKey = key.privateKey.toString('hex')
const publicKey = neoGetPublicKeyFromPrivateKey(neoPrivKey)
const verifiedScript = getVerificationScriptFromPublicKey(publicKey)
const verifiedScript = getVerificationScriptFromPublicKey(publicKey, blockchain)
const scriptHash = reverseHex(hash160(verifiedScript))
const addressVersion = (blockchain && blockchain === Blockchain.NEO3) ? NEO3_ADDR_VERSION : ADDR_VERSION
return {
address: getAddressFromScriptHash(scriptHash),
address: getAddressFromScriptHash(scriptHash, addressVersion),
index,
privateKey: neoPrivKey,
publicKey
Expand Down Expand Up @@ -200,23 +203,6 @@ function generateWalletForCoinType(key: bip32.BIP32Interface, coinType: CoinType
privateKey: key.privateKey.toString('hex'),
publicKey: key.publicKey.toString('hex')
}
// case CoinType.DOT:
// const keypair = dotKeypairFromSeed(key.privateKey)
// return {
// address: keypair.address,
// index,
// privateKey: key.privateKey.toString('hex'),
// publicKey: new Buffer(keypair.publicKey).toString('hex')
// }
// case CoinType.ERD:
// const account = new erdAccount()
// account.loadFromSeed(key.privateKey)
// return {
// address: account.address(),
// index,
// privateKey: key.privateKey.toString('hex'),
// publicKey: account.publicKeyAsString()
// }
default:
throw new Error(`invalid coin type ${coinType} for generating a wallet`)
}
Expand Down
2 changes: 1 addition & 1 deletion src/mpc/generateAPIKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export async function generateAPIKeys(params: GenerateApiKeysParams): Promise<AP
client_secret_share: polygon.client_secret_share,
public_key: polygonWallet.publicKey,
server_secret_share_encrypted: polygon.server_secret_share_encrypted
}
},
},
paillier_pk: btc.paillier_pk,
payload_public_key: payloadSigningKey.publicKey,
Expand Down
4 changes: 3 additions & 1 deletion src/types/MPC.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export enum Blockchain {
BTC = 'BTC',
ETH = 'ETH',
NEO = 'NEO',
NEO3 = 'NEO3',
AVAXC = 'AVAXC',
POLYGON = 'POLYGON'
}
Expand All @@ -17,7 +18,8 @@ export const BlockchainCurve: Record<Blockchain, Curve> = {
[Blockchain.ETH]: 'Secp256k1',
[Blockchain.NEO]: 'Secp256r1',
[Blockchain.AVAXC]: 'Secp256k1',
[Blockchain.POLYGON]: 'Secp256k1'
[Blockchain.POLYGON]: 'Secp256k1',
[Blockchain.NEO3]: 'Secp256r1',
}

export interface PallierPK {
Expand Down

0 comments on commit d61295d

Please sign in to comment.