Mnemonic Wallet(니모닉 지갑)

Hong·2022년 11월 12일
0




💁‍♂️ 니모닉이란(Mnemonic)?

Mnemonic의 어원은 그리스 신화의 기억의 여신 므네모시네(Mnemosyne)에서 유래되었다. 므네모시네의 자녀인 뮤즈(Muses)는 올림포스 신들의 축제에서 아폴론을 도와 음악을 연주 하였는데, 악보가 없는 세계라 기억력에 의존하여 연주할 수 있었다고 한다. 그래서 니모닉이라는 어원은 "기억"에 기반하고 있다.

니모닉 지갑은 기존의 개인 키가 너무 복잡한 형태로 이루어져 있다는(16진수의 매우 긴 문자열) 불편함을 해결하기 위해 등장했다.


기존의 개인 키(Private Key)

21312480152na12312j5bl51hl25vlj12b512b5l1j2b5l125jlb5123j

니모닉(Mnemonic)

endless convince patrol calm apology scene client jungle fitness blind grass pause

👜 니모닉 월렛

이러한 연상 단어를 사용한 지갑을 니모닉 월렛(Mnemonic Wallet)이라고 한다.
니모닉 월렛은 인간에게 더욱 익숙한 영단어로 구성되어 있기 때문에 비밀 키를 더욱 쉽게 관리할 수 있게 해준다.

🏭 니모닉 단어 생성

  1. 128bit 또는 256bit의 난수를 생성한다.
  2. SHA-256 알고리즘으로 해싱하고 해시값에서 (시드 키의 길이) / 32 bit 만큼을 떼어낸다.
    (예를 들어, 난수의 길이가 128bit이라면, 128/32 = 4 임으로 4bit를 앞에서부터 떼어내 checksum을 만든다.)
  3. 체크섬을 기존의 난수 뒤에 붙인다.
  4. 이것을 11bit단위로 잘라낸다. (128bit의 난수가 기존에 존재했다면 4bit의 체크섬을 붙였을 것임으로 132bit의 난수를 11bit로 잘라낸다 132/11 = 12 임으로 난수는 12개로 쪼개진다.)
  5. 나눠진 11bit의 단어를 사전에 정의된 단어로 바꾼다
  6. 니모닉 코드 완성

🥑 니모닉 단어에서 씨드 생성(Mnemonic to Seed)

  1. 니모닉 코드의 단어와(PBKDF2 알고리즘의 첫번째 파라미터)
  2. Salt를 이용해서(PBKDF2 알고리즘 두번째 파라미터)
  3. PBKDF2 알고리즘 함수(SHA-512방식 사용)를 이용해 다시 512bit길이의 난수를 생성

#참고

*SHA-256은 SHA(Secure Hash Algorithm) 알고리즘의 한 종류로서 256비트로 구성되며 64자리 문자열을 반환한다(SHA-512도 마찬가지).

*BIP-39(Bitcoin Improvement Proposal 39)는 니모닉 코드(mnemonic code) 단어를 설명하는 일반적인 산업 표준이다.

*Checksum은 어떤 일련의 데이터에 오류가 존재하는지 확인하기 위한 검사용 데이터]

*Salting은 특정 값에 따라 정해지는 해시값의 추적을 방지하기 위해 원본 데이터에 임의의 문자열인 Salt를 추가하여 해싱하는 방식.

*PBKDF2 알고리즘은 Key Stretching(키 스트레칭) 함수로써 Salting방식을 여러번 반복하는 함수.




CODE

const express = require('express');
const router = express.Router();
const lightwallet = require("eth-lightwallet"); //eth-lightwallet API 설명  https://github.com/ConsenSys/eth-lightwallet#readme
const keyFromPassword = require("eth-lightwallet")
const fs = require('fs');

// TODO : lightwallet 모듈을 사용하여 랜덤한 니모닉 코드를 얻습니다.
router.post('/newMnemonic', async(req,res) => {
    let mnemonic;
    try {
        mnemonic = lightwallet.keystore.generateRandomSeed();
        res.json( {mnemonic} );
    } 
    catch(err) {
        console.log(err);
    }
});

/* 
<니모닉 코드 얻기 수도코드>
mnemonic 변수를 만듭니다
(응답) mnemonic 변수에 lightwallet.keystore.generateRandomSeed()를 담아, mnemonic을 응답으로 전송합니다.
    lightwallet.keystore.generateRandomSeed()는 eth-lightwallet API를 찾아보면 무엇인지 알 수 있다. => generate a new BIP32 12-word seed
(에러) 에러를 응답합니다.
*/

/*
정상적으로 postman에서 요청을 받을 수 있다면 아래와 같은 니모닉코드가 나옴
{
    "mnemonic": "prefer vacuum acid summer sibling execute resist stay much picnic fiber crowd"
}
*/



// TODO : 니모닉 코드와 패스워드를 이용해 keystore와 address를 생성합니다.
router.post('/newWallet', async(req, res) => {
    let password = req.body.password
    let mnemonic = req.body.mnemonic;

    try {
        lightwallet.keystore.createVault(
            {
                password: password,
                seedPhrase: mnemonic,
                hdPathString: "m/0'/0'/0'"
            },
            function (err, ks) {
                ks.keyFromPassword(password, function (err, pwDerivedKey) {
                    ks.generateNewAddress(pwDerivedKey, 1);

                    let address = (ks.getAddresses()).toString();
                    let keystore = ks.serialize();

                    fs.writeFile('wallet.json', keystore, function(err, data) {
                        if(err) {
                            res.json({code:999, message:"fail"});
                        } else {
                            res.json({code:1, message:"success!"});
                        }
                    })
                });
            }
        );
    } catch (exception) {
        console.log("NewWallet ==>>>>" + exception);
    }
});

/*
<니모닉 코드와 password를 이용해 newWallet API만들기 수도코드>
password와 mnemonic을 입력값으로, 서버에 요청을 보냅니다.
    password와 mnemonic 변수를 만듭니다.
    요청에 포함되어 있는 password와 mnemonic을 각 변수에 할당합니다.
(응답) lightwallet.keystore.createVault를 사용하여 키스토어를 생성합니다.
    첫번째 인자(options)에는 password, seedPhrase, hdPathString을 담습니다.
    두번째 인자(callback)에는 키스토어를 인자로 사용하는 함수를 만듭니다.
    eth-lightwallet 모듈의 keystore.keyFromPassword(password, callback) 내장 함수를 사용합니다.
    첫번째 인자에는 password, 두번째 인자(callback)에는 pwDeriveKey를 인자로 사용하는 함수를 만듭니다.
    두번째 콜백함수가 실행되면, eth-lightwallet 모듈의 keystore.generateNewAddress(pwDeriveKey, [num])을 이용해서 새로운 주소 생성 함수를 실행합니다.
    address변수를 만들고, keystore.getAddresses()을 문자열로 할당합니다.
    keystore변수를 만들고, keystore.serialize()을 할당합니다.
    위에서 만들어준 변수를 응답으로 전송합니다.
(오류) 에러를 응답합니다.
*/


/*
<생성된 keystore를 json파일로 만들어 로컬 서버에 저장하기 수도코드>
wallet.js 파일에 fs모듈을 import합니다. (fs 모듈은 Node.js 내장 모듈입니다.)
keyFromPassword의 콜백 함수에서, 으답대신 fs.writeFile 또는 fs.writeFileSync를 사용합니다.
    첫번째 인자에는 .json 형식의 파일이름을, 두번째 인자에는 keystore을 입력합니다.
    세번째 인자에는 응답에 대한 콜백 함수를 입력합니다.
    로컬 서버에 파일을 저장하기 때문에, 응답으로는 성공 또는 실패 메세지만 전송합니다.
*/





module.exports = router;



Postman으로 니모닉 지갑이 잘 생성되는지 서버의 응답확인

아래보면 문자열을 결과값으로 받은 것을 확인할 수 있음



Postman으로 새로운 지갑주소 얻기 응답확인



Postman으로 니모닉 코드와 password입력을 통해 로컬에 keystore생성하기 응답확인

profile
Notorious

0개의 댓글