블록체인 - Mnemonic Wallet 실습

김도영·2022년 6월 22일
0

니모닉(Mnemonic)

니모닉(Mnemonic)이란 결정적 지갑에서 난수를 12개의 영단어로 인코딩한 영단어 그룹으로, BIP39에서 제안되었다. 기존의 시드키는 숫자와 문자로 구성된 난수라 사용자가 사용하기 어려웠지만, 니모닉 코드로 사용자가 기억하기 쉬운 형태로 구성되었다. 블록체인에서 니모닉은 지갑을 복구하기 위한 일반적인 단어들의 조합이다.

니모닉 코드와 시드 생성 9단계

니모닉 코드는 해시 함수를 재귀적으로 반복하는 키 스트레칭 과정을 통해 마스터 시드를 생성하고, 마스터 시드는 HD 지갑 주소 생성의 바탕이 된다.

  1. 128bit 또는 256bit 길이의 난수를 생성한다.
  2. 난수를 SHA-256 알고리즘으로 해싱하고, 해시값에서 (시드 키의 길이) / 32만큼을 떼어낸다. 예를 들어, 난수의 길이가 128bit라면, 해시값에서 128/32인 bit를 앞에서부터 떼어내 체크섬(Checksum)으로 만든다.
  3. 체크섬을 난수의 뒤에 붙인다.
  4. 체크섬을 붙인 난수를 11bit 단위로 잘라낸다.
  5. 각 11bit의 단어를 사전에 정의된 단어로 치환한다.
  6. 각 11bit의 순서를 유지하여 일련의 니모닉 코드를 만든다. 지금까지 과정을 통해 니모닉 코드가 생성되면, 엔트로피와 키 스트레칭 함수 PBKDF2를 사용하여 더 긴(512bit) 시드를 파생시킨다. 여기서 키 스트레칭 함수에는 니모닉 코드솔트(Salt)라는 2가지 파라미터를 넣는다.
  7. PBKDF2 키 스트레칭 함수의 첫 번째 인자는 6단계에서 생성된 니모닉 코드이다.
  8. 두 번째 인자는 솔트이다. 솔트는 문자열 상수 "mnemonic"과 선택적으로 사용자가 지정한 암호문을 연결하여 구성한다.
  9. PBKDF2는 최종적으로 512bit 값을 만드는 HMAC-SHA512 알고리즘으로, 2048해시 라운드를 사용하여 니모닉과 솔트 파라미터를 확ㅈ아하며, 이 결과로 나온 512bit값이 seed이다.

Mnemonic Wallet 실습

Postman 설치

sudo snap install Postman

eth-lightwallet 모듈 설치

npm install eth-lightwallet

beb-sprint-MnemonicWallet/routes/wallet.js

const express = require('express');
const router = express.Router();
const lightwallet = require("eth-lightwallet");
const fs = require('fs');

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


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

    try { // keystore를 생성하는 메소드
        lightwallet.keystore.createVault(
            {
                password: password, // (필수)
                seedPhrase: mnemonic, // (필수) 모든 계정을 생성하는데 사용되는 12단어
                hdPathString: "m/0'/0'/0'" // (필수)HD 경로 문자열
              	// (선택)Salt
            },
            function (err, ks) { // 두 번째 인자에는 keystore를 인자로 사용하는 콜백함수

			// 사용자의 암호를 입력받아 keystore를 암호화
		       		ks.keyFromPassword(password, function (err, pwDerivedKey) {
            // n개의 새로운 주소, 개인 키쌍을 생성하는 함수
                    ks.generateNewAddress(pwDerivedKey, 1);
			// 현재 키 저장소에 저장된 문자열 주소 목록을 반환하여 문자열로 할당
                    let address = (ks.getAddresses()).toString();
                    let keystore = ks.serialize();
                  	
					res.json({ keystore: keystore, address: address });
                });
            }
        );
    } catch (exception) {
        console.log("NewWallet ==>>>> " + exception);
    }
});

module.exports = router;

Postman으로 테스트하여 니모닉 코드 얻기

  1. 로컬 서버를 실행시키고 엔드 포인트(http://localhost:3000/wallet/newMnemonic)를 입력한다.
  2. POST로 send한다.
  3. 서버가 응답하는 니모닉 코드를 확인한다.

Postman으로 keystoreaddress 응답 API테스트

  1. 로컬 서버를 실행시키고 엔드 포인트(http://localhost:3000/wallet/newWallet)를 입력한다.
  2. POST로 서버에 요청
  3. 요청할 때, 위에서 얻은 니모닉 코드를 mnemonic이라는 키 값으로, password는 원하는 비밀번호 입력 후 send 한다.

생성된 keystore파일을 json파일로 만들어 로컬 서버에 저장하기

const express = require('express');
const router = express.Router();
const lightwallet = require("eth-lightwallet");
const fs = require('fs');

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


// 니모닉 코드와 패스워드를 이용해 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:"실패"})
                        } else {
                            res.json({code:1, message:"성공"})
                        }
                    })
                });
            }
        );
    } catch (exception) {
        console.log("NewWallet ==>>>> " + exception);
    }
});

module.exports = router;

로컬 서버의 경로에 파일 생성 확인하기

profile
Blockchain Developer

0개의 댓글