본문 바로가기
프로그래밍/typescsript

[220616] 월렛(블록체인 지갑)의 개념과 구조, 직접 월렛 만들기

by 한코코 2022. 6. 16.

필요한 정보

코어 / 서버 / p2p  && 월렛

월렛은 필수가 아니라서 따로 존재가 가능.

 

보내는사람 : 보내는 사람이 정말로 보내는게 맞는지 인증단계(트랜젝션)

받는 사람 : 받는 사림이 정말로 맞는가?

금액 : 이 금액을 보내는 장소가 정말로 맞는가?

송금/수취인 계좌번호들만 관리하는게 지갑

 

 

 

 

지갑의 구조

 

은행에서 사용하는 걔좌 = 개인키(OTP) + 공개키(은행들끼리 쓰는 코드분류값, 실제 거래에 쓰이는 값)+ 계정(계좌번호)

반드시 블록체인을 거쳐서 만들어야하는게 아님

 

 

 

 

 

개인키 (은행에서 OPT같은 역할)

랜덤으로 64자리의 16진수 문자열을 만들어낸것.

그런데 이 방식은 다른 메인넷을 가지고있는 블록체인, 이더리음같은 블록체인들도 사용하고있는 방식임.

이렇게 만들면 겹칠 위험이 있음.

그래서 다른 정보를 더해서 한번 더 암호화를 돌려주는것 = 공개키.

이런 개인키를 인증하는 방법 = 서명.

 

데이터를 buffer 형태로 주고받는 이유 = 컴퓨터가 알아듣는 언어로 소통해야하기 때문

( 참고 블로그 : https://velog.io/@ragnarok_code/node.js-Buffer-Stream-Binary-Data%EC%9D%B4%EB%9E%80 )

describe('지갑이해하기',()=>{
  let privKey: string
  it('개인키 (privKey',()=>{
    console.log(randomBytes(32))
    console.log(randomBytes(32).toString('hex'))
    
    privKey = (randomBytes(32).toString('hex'))
    console.log(privKey.length)
  })
})


// <Buffer 46 6f 6c 49 64 cc 99 30 25 cb c9 78 3e 8d 7e 73 3a b6 a9 fa df 8e a9 e5 96 a7 b7 e2 bf 1a 71 f6>
// 07179e86b73c34177a7be16169ac72a13775b0cc6cee7206471296c9ffd925d1
// 64

 

 

 

 

공개키 (은행 내부에서 사용하는 코드같은 역할)

개인키가 없으면 거래를 할 수 없는데, 그렇다고 개인키로 직접 거래하는건 보안성으로 매우 위험함

대신 개인키로 디지털서명을 만들어서 거래를 하는것.

공개키를 저장해서 대신 블록체인 거래를 이루어주는게 메타마스크의 역할.

( 참고 블로그 : https://brunch.co.kr/@nujabes403/13 )

 

공개키를 생성하는 순서

1) 랜덤으로 64자리 해시값 생성 = 개인키

2) 개인키를 컴퓨터가 이해할 수 있는 값(keyPair)으로 변환

3) keyPair을 공개키를 추출해서 16진수로 만든 값 = 공개키

4) 완성

 

keyPair

지정된 공개키와 비공개키로부터, 키 페어를 구축하는 생성자. 

    keyPair().getPublic - publicKey

    keyPair().getPrivate - privateKey

이렇게 짝을 이루고 있다.

// elliptic : 랜덤으로 바이트를 뽑아서 16진수로 처리해 리턴해주는 라이브러리
const ec = new elliptic.ec('secp256k1')

// 랜덤으로 바이트를 뽑아줌 -> 32바이트 뽑아서 개인키 만들거임
describe('지갑이해하기',()=>{
  let privKey: string
  it('개인키 (privKey',()=>{
    privKey = (randomBytes(32).toString('hex')) // 사람용
    console.log(privKey.length)
  })

  it('공개키 생성하기', ()=>{
    const keyPair = ec.keyFromPrivate(privKey) // 프로그램용
    pubKey = keyPair.getPublic().encode('hex', true)
    console.log(keyPair)
    console.log(pubKey)
    console.log(pubKey.length)
  })
})

//   KeyPair {
//      ec: EC {
//        curve: ShortCurve {
//          type: 'short',
//          p: [BN].....  이런 엄청 긴 객체 나옴
//
// 03a5e787d62eb4a04af33cf2b76b70f8224ed623e4d41ce8f81cd1452c38a95f2c
// 66

 

 

 

해시값이 64자리인 이유

100원짜리 동전을 256번 던질때 (앞이 1이고 뒤가 0이라고할때) 나오는 값 -> 001001011010... 

2진수 1개로 표현할 수 있는 단위를 1비트라고 하니까 -> 2의 256승 = 256비트

1바이트는 8비트니까 -> 256 / 8 = 32바이트

16진수로 표현한 1자리가 ->  1니블 : 컴퓨터의 기본단위

8비트 = 2니블이니까 -> 4비트 = 1니블

1바이트 = 4비트 2개 = 2니블 = 16진수 2개 = 그래서 16진수로 나타날 수 있는 숫자가 2개

즉, 1바이트 = 2니블

32바이트 * 2니블 = 16진수로 64개

-> 해시값이 64자리인 이유

 

 

 

 

64글자의 해시값이 나온다고했는데 pubKey가 66글자인 이유

0으로 시작하는 두글자 (예 : 01, 04, 03...)은 구별하기위한 고정값이다.

앞 두글자는 빼고 계산한다.

 

 

 

 

서명

개인키와 트랜젝션같은 해시나 데이터가 있어야 만들어지는 서명.

  •     keyPair = 컴퓨터가 알아들을 수 있도록 바꾼값
  •     해시 = 데이터를 SHA256 알고리즘으로 암호화를 한 후 문자열로 변환한 값
  •     signature = elliptic 타원곡선 알고리즘을 통해 개인키와 해시값을 암호화한 16진수 값

나만의 펜(개인키)로 만든 싸인(서명)으로서, 이 거래값(트랜젝션)이 내꺼다!라는 인증을 해시값으로 하는것

서명을 단방향 암호로 만들어서 다시 개인키로 원상복구 할 수 없다.

 

서명을 블록체인에게 넘김 -> 블록체인 : 서명 + 공개키 +  데이터 조합 -> 이게 참인지 거짓인지 구별

it('디지털 서명', () => {
    // 서명을 만들때 필요한 값
    // 개인키
    // 해시값(서명을 할때 넣을 데이터들, transaction hash)
    // privKey = randomBytes(32).toString('hex')
    const keyPair = ec.keyFromPrivate(privKey)
    const hash = SHA256('ingoo').toString()

    // ec.sign(keyPair,hash)와 같음
    // keyPair.sign(hash)
    signature = keyPair.sign(hash, 'hex')
    // 단방향 암호기때문에 서명을 다시 개인키로 돌릴 수 없음.
})

 

 

 

 

계정 (은행 계좌같은 역할)

주소 address 주로 비트 || 계정 account 주로 이더

남들도 알아도 됨.

비트코인의 주소 = 공개키 -> 암호화 메소드 2번

이더리움 계정 = 공개키 -> 32바이트 중에서 12바이트 정도를 잘라낸 나머지 40글자

고정값도 빼내야하니까 코드상에서는 26글자(13바이트*2)를 잘라내었다.

it('계정만들기',()=>{
    const buffer = Buffer.from(pubKey)
    const address = buffer.slice(26).toString()
    console.log(address)
    console.log(address.length)
})

// 148a6abafe29d0f8e15ba0e1d07aa3bf0408c29d
// 40

 

 

 

 

트랜젝션 (거래내용같은 데이터)

트랜젝션의 값을 모두 가져와서 해시처리해서 나온 해시값 = 인덱스

고유키값으로 인덱싱하는 이유 : 동시다발적으로 트랜젝션이 발생하기 때문에 순서대로 숫자를 매겨서 인덱싱을 할 수 없다.

어 그러니까 내 돈은 비트코인 네트워크에 있고 지갑은 잔액만 보여주는 수단 -> 이 과정이 트랜젝션

 

 

 

 

 

비트코인의 거래법

여태까지 거래한 모든 히스토리를 다 검색해서 그에 맞는 값을 가져옴

 

input : [객체] -> 속성명 : 서명(=시그니처, 너 개인키 있니없니?정도)...

outout : [객체] -> 속성명 : address(가지고있는 총 주소중에서 얼마만큼을 남길거니?)...

예)  A 50 / C 0 -> C에게 5를 줌 -> A 45 / C 5 이 과정을 output으로 넘김

 

내게 보여주는 잔액 = 모든 입금 - 모든 출금

단점 : 느림 / 장점 : 돈의 계산법에 대해서는 정확함

( https://www.blockchain.com/btc/tx/d51ba1bc67728ad1935b1cd111db7320548eb97dab50cdb96145b8530c7d43f3 )

 

 

 

이더리움의 거래법

게임속 재화계산법처럼 결과만 남음

단점 : 중간계산관계모름...?/ 장점 : 빠름

이더리움 트랜젝션

 

 

 

 


정리

1. 지갑은 각각 다른 사람이 만들 수 있다

2. 개인키는 누구나 만들 수 있다

3. 공개키는 개인키로 만든다

4. 계좌는 공개키에서 12글자정도 빼서 만든다. 계좌는 평생 계좌다!

댓글