마스터링 이더리움에서 캐빈 우드가 정의하기론
결정적 지갑을 파생하기 위해 시드로 사용되는 난수를 인코딩하는 단어 시퀸스다. 단어 시퀸스는 시드를 다시 만들어내고, 이 시드로부터 지갑과 모든 파생된 키들을 재생성할 수 있다.
아직 결정적 지갑이 뭐지?라는 의문이 들것이다. 그렇다면 결정적 지갑에 대해서 먼저 알아보자.
지갑은 이더리움의 주요 사용자 인터페이스를 제공하는 소프트웨어 어플리케이션으로 사용자의 개인키를 담는 공간이자 키를 관리하는 시스템이다.
일반적으로 많은 사람들이 오해하는 것이 이더리움 지갑이 이더 혹은 토큰 자체를 보관하고 있다고 생각한다. 그러나 그것은 사실이 아니다. 사실 지갑은 단지 키만 보유하고 있을 뿐이다.
- 비결정적 지갑 - 각기 다른 무작위 수로부터 각각의 키를 무작위적으로 추출하는 지갑 쉽게 생각하자면 옛날에 사람들이 많이 들고 다니던 열쇠뭉치를 생각하면 됨. 그래서 JBOK 지갑이라고 불리기도함. 이 개인키들은 각각 전혀 상관이 없음.
장점 : 극강의 익명성
단점 : 분실하게 되면 절대 찾을 수 없음. 정기적인 백업 필요.
- 결정적 지갑 -단일 시드 키로부터 파생된 개인키들로 사용.
장점 : 하나의 시드 키만 가지고 있으면 전체 지갑에 접근이 가능함.그래서 사용하기 쉬움.
단점 : 시드키를 도난당하면 지갑 전체가 위험.그러나 시드키만 보안에 신경쓰면 되기에 더 보안적이라는 이야기도....
실생활의 예로 들어보자.
비결정적 지갑은 열쇠뭉치, 결정적 지갑은 호텔에서의 마스터키라고 생각하면 된다.
어릴 적 열쇠 뭉치를 들고 다닌 적이 있을 것이다. (필자는 93년생...) 각각의 열쇠는 서로 전혀 관련이 없다. 집문의 열쇠는 집에 들어 갈 수 있는 역할을 하고 자전거 자물쇠 열쇠는 자전거자물쇠만 열수 있다.
결정적 지갑은 호텔 마스터키라고 생각하면 된다. 이런 장면을 본적이 있거나 경험해본 적이 있을 것이다. 우리가 호텔에 체크인을 했다. 키를 받았고 그걸로 자유롭게 출입을 할 수 있다. 그런데 외출했다가 키를 잃어버렸다. 그러면 우리는 프론트에 이야기 하면 호텔리어가 마스터키로 쉽게 열어준다. 이 때 마스터키처럼 사용되는 것이 시드키다.
이제 비결정적 지갑과 결정적 지갑이 뭔지 조금 알아봤다. 그렇다면 니모닉이라는 것에 대해 조금 가까워졌다.
니모닉은 시드키를 쉽게 보관하기 위해서 만들어진 것이다. 개인이 난수를 외우기란 굉장히 힘들다. 2030101829031827913879874901870d189012987a987a 이런 난수를 타이핑 하는 것은 굉장히 어렵다... 지갑을 옮기거나 할때
그런데 만약 cake apple borrow silk endorse fitness top denial coil riot stay wolf luggauge oxygen faint major edit measure invite love trap filed 같은 단어 쉬킨스만 알고 있으면 시드키를 파생시킬 수 있으면 얼마나 편하겠는가?
그런데 이런 단어 시퀸스만으로 시드키를 만들게 된다면 굉장히 위험하다. 니모닉 코드를 보관하는 파일이 해킹당하거나 하면 내 지갑의 모든 이더들이 위험해진다!!!!
var express = require('express');
var router = express.Router();
const lightwallet = require('eth-lightwallet');
const fs = require('fs');
router.post('/newMnemonic', async (req, res) => {
try {
const mnemonic = lightwallet.keystore.generateRandomSeed();
res.json({ mnemonic });
} catch (err) {
console.log(err);
}
});
//니모닉 코드는 eth-lightwallet 라이브러리에서 쉽게 만들 수 있다.
요청을 할 때마다 다른 니모닉이 생성된다. 다른 니모닉이 생성된다는 것은 니모닉 코드 생성시 계속 다른 무작위 난수를 사용한다는 것을 의미한다.
사실 니모닉 지갑은 니모닉만으로 시드키를 파생시키지 않는다. 니모닉 코드 + salt(개인 비밀번호)를 통해서 시드키가 파생된다.
router.post('/newWallet', async (req, res) => {
const { password, mnemonic } = req.body;
try {
lightwallet.keystore.createVault(
{
password: password,
seedPhrase: mnemonic,
hdPathString: "m/0'/0'/0'",
},
(err, ks) => {
ks.keyFromPassword(password, (err, pwDerivedKey) => {
ks.generateNewAddress(pwDerivedKey, 1); //자식키 생성 갯수
let address = ks.getAddresses().toString();
let keystore = ks.serialize();
console.log(ks)
fs.writeFile('wallet.json', keystore, (err, data) => {
if (err) {
res.json({ code: 999, message: '실패' });
} else {
res.json({seed:ks.encPrivKeys,code:1,message:'성공'});
}
});
});
}
);
} catch (exception) {
console.log('NewWallet ==>>>> ' + exception);
}
});
module.exports = router;
이 코드를 실행하게 되면 wallet.json 파일이 생기고 keystore를 serialize 된 값이 작성이 된다.
밑의 코드는 console.log(ks) 한 결과다.
KeyStore {
salt: 'rWKIyInkKeX5fKM/nk/HfKRdcJ+qbDqx1M3v9KyLWGo=',
hdPathString: "m/0'/0'/0'",
encSeed: {
encStr: 'JVSb34JPhIdEHCAWgl0bNiQ+XRsUIcuo/iAuPXLz2OuBR4fjz6MFdYsGXupBceTKDb76KzSLia/PPgqEk4eK61guo+nZX8Y0L45QviOcioLDL82VqFFnngmZ5RtXh0vUs/lquUHeAwRhtULtUsSsO1Tfv0lRljoz0LDGxZs7P/LtaBRMow8sGg==',
nonce: 'cQ9A4a7USsEOPEJ6LsaEFPihHKBNH9Sr'
},
encHdRootPriv: {
encStr: '8hA4s+FraHEkVr8QMIr1MBiOrrMxqRZTihR5DROu4+QxFKqBO9LYs3CjCKe3U5YOU5g9GGLYIjFzV2oPV9hTP9/4K6Vf+bdNUXMO9Kp5YqjyhZdy4TI4jg3IvWqkwLLtv3CJpAvYSKLo3eaQ7cYxlgXIqIpgpRX2oLOZidh1jQ==',
nonce: '+TaudpTKX7He1GhFwcI4P7ZMpq7yKcMC'
},
version: 3,
hdIndex: 1,
encPrivKeys: {
'3a800dd196a125f3afdec47b76c747b8218f2791': {
key: '8ORHvr0JujYy0ExqaBsyh09vP6uB/CpvqdevUMiJ4mOR5V/+QxCd8Qm7CVdli7XX',
nonce: 'UCnY9weHPaXp9ZWymtBzmhF96HC5X3P3'
}
},
addresses: [ '3a800dd196a125f3afdec47b76c747b8218f2791' ]
}
여기서 시드 값이 뭘까? 되게 궁금해서 찾아봤는데 공식문서에도 내용은 없었다...
처음에는 encSeed.encStr 이 시드키인 줄 알았다. 그런데 확실치 않아서 포스트맨을 활용해 바뀌지 않는 값이 seed키일 것 같아서 한번 계속 찍어보면서 비교해봤다.
계속 찍어봤을 때 바뀌지 않는 값이 encPrivKeys 였다.
seed 값은 내가 준 키값이고 그 안에 내용은 ks.encPrivKeys 이다. 3a800dd의 문자열이 seed 키로 추정된다.
니모닉 + salt 가 동일한데 seed키가 계속 다르게 생성이 된다면 아마 필요없는 기술아닐까?
해시함수의 특성을 생각한다면 같은 입력값이 들어가면 똑같은 출력값이 나와야하기에 내가 발견한 seed 키가 아마 실제 wallet에 사용되는 키라고 나는 확신한다.(아닐수도?)
사실 마스터링 이더리움을 읽으면서 내가 이런걸 다 만들 수 있을까? 라는 걱정이 많았다. 그런데 막상 만들어보니 이론이 바탕이 됬을 때 더 잘할 수 있다는 것을 느꼈다.
만약 책을 안읽고 기본 개념이 안잡혔을 때 이런걸 만들라고 했으면 정말 많이 헤맸을 것이다.역시 뭐든 이론은 기본 밑바탕이 되어야 하나보다.
탄탄한 기초지식이 바탕이 되었을 때 더 쉽게 할 수 있으며, 더 쉽게 이해하고, 더 쉽게 개발할 수 있다는 것을 느끼는 하루였다.