Symbol from NEM や mijin Catapultで使用するアカウント関連情報まとめ


今回はSymbol from NEM やmijin Catapult で使用するアカウント関連情報のまとめです。
秘密鍵、公開鍵、アドレスなどの生成、QRコード、ニーモニックなどアカウントを管理するための方法について説明します。

# 事前準備

### 必要なもの
インターネット接続環境
Google Chromeブラウザ

### 使用するツール・ライブラリ

[symbol-sdk-typescript-javascript](https://github.com/nemtech/symbol-sdk-typescript-javascript)
[symbol-qr-library](https://github.com/nemtech/symbol-qr-library)
[symbol-hd-wallets](https://github.com/nemtech/symbol-hd-wallets)

nemtechレポジトリが公開している上記ライブラリをbrowserify化した
[symbol-sdk-pack-1.0.0.js](https://github.com/xembook/nem2-browserify/blob/master/symbol-sdk-pack-1.0.0.js)を使用します。

# 開発者コンソール起動とsymbol-sdkの準備

### 開発者コンソールの起動


Google Chrome ブラウザを起動しノードにアクセスしてF12キーを押して開発者コンソールを開きます。

私の検証用ノードです（メインネット）

https://node.xembook.net/


### 設定値の定義とライブラリの埋め込み

コンソールに以下のスクリプトをコピーして貼り付けます。


```js
NODE = window.origin;

(script = document.createElement('script')).src = 'https://xembook.github.io/nem2-browserify/symbol-sdk-pack-1.0.0.js';
document.getElementsByTagName('head')[0].appendChild(script);
```

- NODE
    - 接続するノードのURL
- script
    - browserify化したsymbol-sdkを読み込むスクリプトタグを表示中のページに埋め込みます


![スクリーンショット 2020-09-28 23.43.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29187/44df9d95-cc45-17ed-bd69-93b9562b11b5.png)

スクリプトタグが無事に埋め込まれました。
このようにコンソールには最後に実行されたコマンドの結果が出力されるようになっています。


### ライブラリのインポート

```js
nem = require("/node_modules/symbol-sdk");
qr = require("/node_modules/symbol-qr-library");
hd = require("/node_modules/symbol-hd-wallets");

repo = new nem.RepositoryFactoryHttp(NODE);
generationHash = await repo.getGenerationHash().toPromise();
networkType = await repo.getNetworkType().toPromise();
```

# [Accountクラス](https://docs.symbolplatform.com/symbol-sdk-typescript-javascript/1.0.0/classes/_model_account_account_.account.html)
Accountは秘密鍵を知っているユーザだけが生成できる、トランザクション署名などに使用するクラスです。
後述するQRコードにパスフレーズで暗号化して埋め込んだり、さらに上位に位置するニーモニックで復元されるHDウォレットなどから導出したりすることが可能です。

### 新規作成

```js
alice = nem.Account.generateNewAccount(networkType);
```

### 秘密鍵から復元

```js
alice = nem.Account.createFromPrivateKey(
  "01E2597D5B3A11502B121AD994F67D27A1662C4FAF9D1DA1A4E57600BD65853C",
  networkType
)
```

### 秘密鍵の導出

```js
alice.privateKey
```
> 01E2597D5B3A11502B121AD994F67D27A1662C4FAF9D1DA1A4E57600BD65853C

### 公開鍵の導出
```js
alice.publicKey
```
> 749D1BD458E055F3A76D34FB33DA9CBD5E55AFAC4902A0BBE45620F48C48BDA0


# [PublicAccountクラス](https://docs.symbolplatform.com/symbol-sdk-typescript-javascript/1.0.0/classes/_model_account_publicaccount_.publicaccount.html)
PublicAccountクラスは署名検証に利用する重要なクラスです。
検証のほかにもアグリゲートトランザクションにて他者の署名を要求したい用途にも使用します。

### Accountクラスから導出
```js
alice.publicAccount
```
### PublicAccountから公開鍵の導出
```js
publicAlice = alice.PublicAccount;
publicAlice.publicKey
```
> 749D1BD458E055F3A76D34FB33DA9CBD5E55AFAC4902A0BBE45620F48C48BDA0

### 公開鍵から生成
```js
nem.PublicAccount.createFromPublicKey(
  "749D1BD458E055F3A76D34FB33DA9CBD5E55AFAC4902A0BBE45620F48C48BDA0",
  networkType
)
```


# [Addressクラス](https://docs.symbolplatform.com/symbol-sdk-typescript-javascript/0.21.0/classes/_model_account_address_.address.html)
Addressクラスは送信先の指定に使用するクラスです。
様々な表現方法があり、用途に応じて変換をかける必要があります。

### Addressクラスからテキストへの変換
#### plain address
```js
alice.address.plain()
```
> TD6EVQBWBBS3ELM5RVPRSIFQXW7IN57LHKTJM2Y

#### pretty format address
```js
alice.address.pretty()
```
> TD6EVQ-BWBBS3-ELM5RV-PRSIFQ-XW7IN5-7LHKTJ-M2Y

#### encoded address
```js
alice.address.encoded()
```
> 98FC4AC0360865B22D9D8D5F1920B0BDBE86F7EB3AA6966B

encoded addressは普段見かけることはありませんが、ノードのエンドポイントから直接APIでアドレス情報を取得した場合はこのフォーマットで出力されています。

### Addressクラスへの変換

#### encoded addressから

```js
nem.Address.createFromEncoded("98FC4AC0360865B22D9D8D5F1920B0BDBE86F7EB3AA6966B")
```

#### plain addressから
```js
nem.Address.createFromRawAddress("TD6EVQBWBBS3ELM5RVPRSIFQXW7IN57LHKTJM2Y")
```

#### PublicAccountクラスから

```js
publicAlice.address
```

### [RawAddress変換](https://docs.symbolplatform.com/symbol-sdk-typescript-javascript/1.0.0/classes/_core_format_rawaddress_.rawaddress.html)

RawAddressはトランザクションをノードにアナウンスする際のアドレス情報をシリアライズする時に使用されます。普段使用することはありませんが、トランザクションのPayloadを読み解く必要が出てきた場合は知っておく必要があります。

#### plain address から Uint8Arrayへの変換
```js
uint8Address = nem.RawAddress.stringToAddress(alice.address.plain())
```
> Uint8Array(24) [152, 252, 74, 192, 54, 8, 101, 178, 45, 157, 141, 95, 25, 32, 176, 189, 190, 134, 247, 235, 58, 166, 150, 107]

#### Uint8Array から plain address への変換

```js
nem.RawAddress.addressToString(uint8Address)
```
> TD6EVQBWBBS3ELM5RVPRSIFQXW7IN57LHKTJM2Y

# AccountQR生成

symbol-qr-libraryを使用してQRコードの生成、そこからアカウントクラスを復元します。

### QRコード生成
```js
aliceQR = new qr.AccountQR(alice,"パスフレーズ",networkType);
aliceQR.toBase64().subscribe(x => {
  (tag= document.createElement('img')).src = x;
  document.getElementsByTagName('body')[0].appendChild(tag);
});
```

### QRコードからAccountクラスを復元する
```js
jsonQR = aliceQR.toJSON()
aliceQR = qr.AccountQR.fromJSON(jsonQR ,"パスフレーズ");
alice= aliceQR.account;
```

# ニーモニック

symbol-hd-walletsを利用してニーモニックを生成、アカウントを導出します。

### ニーモニック生成
```js
mnemonic = hd.MnemonicPassPhrase.createRandom();
```
> MnemonicPassPhrase {plain: "stick panel thought level stamp city dynamic nasty… evoke govern shoot spy family when master oppose"}



### エントロピーを利用したニーモニック生成
```js
(script = document.createElement('script')).src = 'https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.min.js';
document.getElementsByTagName('head')[0].appendChild(script);
//一度ここで改行
entropy = CryptoJS.SHA256("エントロピー" + nem.Crypto.randomBytes(8)).toString();
mnemonic = hd.MnemonicPassPhrase.createFromEntropy(entropy)
```


### アカウント生成
```js
aliceSeedHex = mnemonic.toSeed('パスフレーズ');
aliceKey = hd.ExtendedKey.createFromSeed(aliceSeedHex , hd.Network.SYMBOL);
aliceWallet = new hd.Wallet(aliceKey.derivePath("m/44'/4343'/0'/0'/0'"));
alice = nem.Account.createFromPrivateKey(wallet.getAccountPrivateKey(), networkType);

```

ニーモニックからアカウントを導出します。パスフレーズは省略可能です。

### アカウント復元
```js

mnemonic = new hd.MnemonicPassPhrase(
  "stick panel thought level stamp city dynamic nasty want suggest goose actress sugar clap small clinic evoke govern shoot spy family when master oppose"
);

aliceSeedHex = mnemonic.toSeed('パスフレーズ');
aliceKey = hd.ExtendedKey.createFromSeed(aliceSeedHex , hd.Network.SYMBOL);
aliceWallet = new hd.Wallet(aliceKey.derivePath("m/44'/4343'/0'/0'/0'"));
alice = nem.Account.createFromPrivateKey(wallet.getAccountPrivateKey(), networkType);

//オプトインアカウントを復元する場合はhd.Network.BITCOINに変更

```


### 子アカウント生成

```js
wallet = new hd.Wallet(xkey.derivePath("m/44'/4343'/1'/0'/0'"));
account = nem.Account.createFromPrivateKey(aliceWallet.getAccountPrivateKey(), networkType);
```

44は[SLIP44](https://github.com/satoshilabs/slips/blob/master/slip-0044.md)(SatoshiLabs improvement proposals)を意味しています。
4343はSymbolのcoin typeを意味しています。

### ニーモニックをQRコードで出力する

```js
mnemonicQR = new qr.MnemonicQR(mnemonic, 'パスフレーズ', networkType,generationHash);

base64 = mnemonicQR.toBase64().subscribe(x => {
  (tag= document.createElement('img')).src = x;
  document.getElementsByTagName('body')[0].appendChild(tag);
});

```

### QRコードからニーモニックを復元する

```js
jsonQR = mnemonicQR.toJSON();
qr.MnemonicQR.fromJSON(jsonQR,'パスフレーズ');
```