728x90

겨우됐다 지갑생성하기....

 

chainedBlock에 

return을 빼먹어서 였음...

 

chainedBlock.js 코드전체

더보기
const fs = require('fs')
const merkle = require('merkle')
const cryptojs =require('crypto-js') 
// const { randomBytes } = require('crypto')
const random = require('random')
const { get } = require('http')

//예상 채굴 시간과 난이도 조절 단위수를 변수로 설정한다
const BLOCK_GENERATION_INTERVAL = 10  //second
const DIFFICULT_ADJUSTMENT_INTERVAL = 10 //in blocks




//블럭 형태 (헤더, 바디)
class Block{
        constructor(header, body){
		this.header = header
		this.body = body
	}
}

class BlockHeader{
        constructor(version,index, previousHash, timestamp, merkleRoot,difficulty, nonce){
	     this.version = version
	     this.index = index
	     this.previousHash = previousHash
	     this.timetamp = timestamp //블럭만들어진 시간
	     this.merkleRoot = merkleRoot
	    //  this.bit = bit
		this.difficulty = difficulty //채굴난이도. 아직안씀
	     this.nonce = nonce //넌스(문제풀기위해 대입한 횟수) 아직 안씀

	}
}

//버전계산하는 함수 
function getVersion(){
	const package = fs.readFileSync("package.json")
	// console.log(JSON.parse(package).version)
	return JSON.parse(package).version

}


//getVersion()

function createGenesisBlock(){
	const version = getVersion()
	const index= 0 //맨처음이라 인덱스0
	const previousHash = '0'.repeat(64) //sha256암호가 64자리니까 0을 64자리로 바꿔줌
	// const timestamp = parseInt(Date.now()/1000)
	//비트코인 날짜로..비트코인최초탄생일 2009/01/03 6:15pm (UTC)
	const timestamp = 1231006505  
	const body = ['제네시스블록 바디임요']
	const tree = merkle('sha256').sync(body) //바디값불러와서 sha256으로 암호화
	const merkleRoot = tree.root() || '0'.repeat(64)
	//루트값없으면 || 뒤에값 출력
	const difficulty = 0 //헤더값에 난이도 아직 0임
	const nonce = 0

	// console.log("version : %s, timestamp: %d, body : %s",version,timestamp,body)
	// console.log("previousHash : %d", previousHash);
	// console.log("merkleRoot : %d", merkleRoot);

	const header = new BlockHeader(version,index, previousHash, timestamp, merkleRoot, difficulty,nonce)
	return new Block(header, body)

}

//const block = createGenesisBlock()
//console.log(block)


//블록저장할수있는애들, 여러개 들어갈 수 있는 배열을 만들어줌
let Blocks = [createGenesisBlock()]


//현재 있는 블록을 다 리턴해주는 함수, 블럭목록 부르는 함수
function getBlocks(){
	return Blocks
}
//제일 마지막에 만든 블록 가져오기
function getLastBlock(){
	//길이 1이니까 1-1 =0 즉 첫번째배열 불러와 
	return Blocks[Blocks.length - 1]

}

//data에는 블록이 들어오는거임, 이블록을 가지고 해시값을 만들어내는 것임
// function createHash(data){
// 	const {version, index,previousHash,timestamp,merkleRoot,difficulty,nonce}= data.header
// 	const blockString = version + index + previousHash + timestamp + merkleRoot + difficulty + nonce
// 	const hash = cryptojs.SHA256(blockString).toString()
// 	return hash
// }
function createHash(data){
	//인자로 받은 것중에 헤더를 뽑아내서
	const {version, index, previousHash, timestamp, merkleRoot, difficulty, nonce} = data.header
	const blockString = version + index + previousHash + timestamp + merkleRoot + difficulty + nonce
	//다 합쳐서 해시로 만들고 리턴
	const hash = cryptojs.SHA256(blockString).toString()
	return hash
}

function calculateHash(version, index, 
		previousHash,timestamp,merkleRoot,difficulty,nonce){
//헤더의 값에 nonce값을 추가해서 모두 더한 string을 가지고 암호화 
//한 결과 hash를 내보낸다
	const blockString = version + index + previousHash + timestamp + merkleRoot + difficulty + nonce
	const hash = cryptojs.SHA256(blockString).toString()
	return hash
}
// const genesisBlock =createGenesisBlock()
//const testHash = createHash(block)
// console.log(genesisBlock)


//다음블록 만들었을 때 기존 블록 정보 가져와
function nextBlock(bodyData){
	//마지막 블럭, 이전블록으로
	const prevBlock = getLastBlock()
	const version = getVersion()
	const index = prevBlock.header.index + 1
	//이전 블록의 해시값
	const previousHash = createHash(prevBlock)
	const timestamp = parseInt(Date.now()/1000)
	const tree = merkle('sha256').sync(bodyData)
	const merkleRoot = tree.root() || '0'.repeat(64)
	//난이도 조절하는 함수 추가 
	const difficulty = getDifficulty(getBlocks())
    // const nonce = 0
    // const header = new BlockHeader(version, index, previousHash,timestamp,merkleRoot,bit,nonce)
	const header = findBlock(version, index, 
		previousHash,timestamp,merkleRoot,difficulty)
	return new Block(header,bodyData)


}
// const block1 = nextBlock(["tranjaction1"])
// console.log(block1)


function addBlock(bodyData){
	const newBlock = nextBlock(bodyData)
	Blocks.push(newBlock)
}
// addBlock(['transaction1'])
// addBlock(['transaction2'])
// addBlock(['transaction3'])
// addBlock(['transaction4'])
// addBlock(['transaction5'])
// console.log(Blocks)

//0103
// function replaceChain(newBlocks){
// 	if (isValidChain(newBlocks)){
// if 	((newBlocks.length> Blocks.length) ||
// (newBlocks.length=== Blocks.length) && random.boolean()){
// 	Blocks = newBlocks
// 	broadcast(responseLatestMsg())
// 	} 
// }
// 	else {
// 		console.log("받은 원장에 문제가 있음")
// 	}
// }
function hexToBinary(s) {
	//헤더부분을 sha256 암호화한 결과
	//16진수 64자리를 2진수로 변환하기
	const lookupTable = {
		'0' : '0000', '1' : '0001', '2': '0010', '3' : '0011',
		'4' : '0100', '5' : '0101', '6': '0110', '7' : '0111',
		'8' : '1000', '9' : '1001', 'A': '1010', 'B' : '1011',
		'C' : '1100', 'D' : '1101', 'E': '1110', 'F' : '1111'
	}

	let ret = "";
	for(let i = 0; i < s.length; i++){
		if (lookupTable[s[i]]) {
			ret += lookupTable[s[i]];
		}
		else { return null; }
	}
	return ret;
}
function hashMatchesDifficulty(hash, difficulty) {
	//difficulty를 이용해 만든 조건을 만족하는지 hash값과 대조해
	//조건에 해당되면 블록 생성
	const hashBinary = hexToBinary(hash.toUpperCase())
	 //difficulty 난이도가 높아짐에 따라 0개수가 늘어남 
	const requirePrefix = '0'.repeat(difficulty)
	//높으면 높을수록 조건을 맞추기가 까다로워짐(nonce값과 time값이 바뀌면서 암호화값이 달라진다.)
	return hashBinary.startsWith(requirePrefix)

}

function findBlock(currentVersion, nextIndex, previousHash, nextTimestamp,
	merkleRoot, difficulty) {
		//calculateHash값이 조건이 맞을때까지 while문으로 반복
		//조건문 반복할때마다 nonce값 증가
		let nonce = 0;
		while (true) {
			var hash = calculateHash(currentVersion, nextIndex, previousHash, nextTimestamp,
				merkleRoot, difficulty,nonce)
				if (hashMatchesDifficulty(hash,difficulty)){
					return new BlockHeader(currentVersion, nextIndex, previousHash, nextTimestamp,
						merkleRoot, difficulty,nonce)

				}
				nonce++ ;
				
		}
	}

	function getDifficulty(blocks){
		const lastBlock = blocks[blocks.length -1]
		if (lastBlock.header.index !==0 && lastBlock.header.index
			% DIFFICULT_ADJUSTMENT_INTERVAL === 0){
				//마지막 블럭헤더인덱스가 0이 아니고
				//난이도 조절수만큼 나누고 나머지가 0이면

				//난이도 조정함수 실행
				return getAdjustDifficulty(lastBlock,blocks)
			}
			//난이도 리턴
			return lastBlock.header.difficulty
	}

	function getAdjustDifficulty(lastBlock, blocks){
     // 지금 블록에서 난이도 조절 단위 수만큼의 전 블록과의 time 
	 //즉, 생성시간을 비교해서 자신의 예상 시간보다 느리거나 빠르면 난이도를 조절한다.
    //적당하면 난이도가 유지되고 블럭의 생성시간이 느리면 난이도를 낮추고, 빠르면 난이도를 높인다.
		const preAdjustmentBlock = blocks[blocks.length - DIFFICULT_ADJUSTMENT_INTERVAL];
		//시간
		const elapsedTime = lastBlock.header.timestamp - preAdjustmentBlock.header.timestamp
		const expectedTime = BLOCK_GENERATION_INTERVAL * DIFFICULT_ADJUSTMENT_INTERVAL;

		if (elapsedTime/2 > expectedTime) {
			return preAdjustmentBlock.header.difficulty +1;
		}
		else if (elapsedTime * 2 < expectedTime){
			return preAdjustmentBlock.header.difficulty -1 
		}
		else {
			return preAdjustmentBlock.header.difficulty
		}
	}

	function getCurrentTimestamp(){
		//Math.round 반올림함수
		return Math.round(Date().getTime()/ 1000);
	}

	function isValidTimestamp(newBlcok, prevBlock){
		if (newBlock.header.timestamp - prevBlock.header.timestamp > 60)
			return false
		if (getCurrentTimestamp()- newBlock.header.timestamp > 60)
		    return false
		return true
		

	}




module.exports = { hashMatchesDifficulty, isValidTimestamp, getBlocks, createHash,
	 Blocks, getLastBlock, nextBlock, addBlock, getVersion, 
	 createGenesisBlock };    //내보내주는거

httpServer.js

더보기
const express = require("express")
const bodyParser = require("body-parser")
const {getBlocks, nextBlock,getVersion} = require('./chainedBlock.js')
const {addBlock}= require('./checkValidBlock')
const { connectToPeers, getSockets } = require("./p2pServer.js")
const {getPublicKeyFromWallet, initWallet} = require("./encryption")

const http_port = process.env.HTTP_PORT || 3001

function initHttpServer(){
	const app = express()
	app.use(bodyParser.json())
	//추가
	app.post("/addPeers", (req,res)=>{
		const data = req.body.data || []
		console.log(data);
		connectToPeers(data);
		res.send(data);

	})
	app.get("/peers", (req, res)=> {
		let sockInfo = []

		getSockets().forEach(
			(s)=>{
				sockInfo.push(s._socket.remoteAddress+":"+s._socket.remotePort)
			}
		)
		res.send(sockInfo)
	})

	app.get("/blocks",(req,res)=>{
 
		res.send(getBlocks())

	})
	app.get("/version",(req, res)=>{
		res.send(getVersion())
	})

	app.post("/mineBlock",(req,res)=>{
		const data = req.body.data || []
		console.log(data)
		const block = nextBlock(data)
		addBlock(block)
		// res.send(block)
		res.send(getBlocks())
	})

	app.post("/stop", (req,res)=>{
		res.send({"msg":"Stop Server!"})
		process.exit()
	})
	app.get("/address", (req,res)=>{
		initWallet()
		const address = getPublicKeyFromWallet().toString();
		console.log(getPublicKeyFromWallet())
		if(address != "") {
			res.send({"address" : address})
		}
		else {
			res.send("empty address!")
		}
	})
	app.listen(http_port,()=>{
		console.log("Listening Http Port : "+ http_port)
	})


}

initHttpServer()

 

encryption.js

더보기
const fs = require("fs")
//타원곡선개념을 사용한 디지털 터널알고르짐을 짤거임
//타원 곡선 디지털 서명 알고리즘
const ecdsa = require("elliptic")
const ec = new ecdsa.ec("secp256k1")

const privateKeyLocation = "wallet/"+
(process.env.PRIVATE_KEY || "default");
const privateKeyFile = privateKeyLocation + "/private_key"


function initWallet(){
    if (fs.existsSync(privateKeyFile)){
        console.log("기존 지갑 private key 경로 :" + privateKeyFile)
        return;
    }
    if (!fs.existsSync("wallet/")){
        fs.mkdirSync("wallet/")
    }
    if (!fs.existsSync(privateKeyLocation)){ //wallet/default 파일없다면
        fs.mkdirSync(privateKeyLocation)
        //만들어줘.
       
    }
    if (!fs.existsSync(privateKeyFile)){//프라이빗키없으면
        console.log('주소값 키값을 생성중')
        const newPrivatekey = generatePrivatekey()
        fs.writeFileSync(privateKeyFile, newPrivatekey)
        console.log('개인키 생성이 완료됐습니다')

    }
    const newPrivatekey = generatePrivatekey()
    fs.writeFileSync(privateKeyFile,newPrivatekey)
    console.log("새로운 지갑 생성 private key 경로 :" + privateKeyFile)

}

// initWallet()

//비밀키 생성
function generatePrivatekey(){
    const keyPair = ec.genKeyPair();
    const privateKey = keyPair.getPrivate();
    //16진수로 만들어서 리턴
    return privateKey.toString(16);
}
//비밀키(인증서) 출력하는 함수
function getPrivateKeyFromWallet(){
    //지갑에 만들어놓은 걸 읽을 수 있게 해줌
   const buffer = fs.readFileSync(privateKeyFile,"utf8")
   return buffer.toString();
}
//공개키(지갑주소) 만들기
function getPublicKeyFromWallet(){
    const privateKey = getPrivateKeyFromWallet();
    const key = ec.keyFromPrivate(privateKey, "hex");
    return key.getPublic().encode("hex")
}

module.exports= {getPublicKeyFromWallet,initWallet}

 

 

 

node node httpServer.js

로 실행.

 

 

 

 

 

 

 

1. 암호화 종류

단방향 암호화 : 오직 암호화만 가능

양방향 암호화 : 암호화하고 다시 복호화 가능

 

양방향에 경우 당사자 2명을 제외한 나머지 사람들이 몰라야하므로 

비밀키를 정한다. 하지만 이 비밀키를 알 수 있기 때문에 당사자 2명 각각 서로 다른 키를 가진다. 

비대칭키 암호(공개키,비밀키)

 

 

2. 공개키 알고리즘

 

공개키 알고리즘은 크게 두 가지 방식으로 분류됨

1. 소인수분해 문제를 이용해서 만들어지는 것

2. 이산 로그 문제를 이용해서 만드는 방법 입니다. (타원곡선 )

 

 

 

3. 디지털 서명

 

 

4. ECDSA 알고리즘

타원곡선 암호를 전자서명에 접목시킨 암호 알고르짐

비대칭키 암호에 해당

secp256k1 라는 기준에 맞춰진 방정식 사용

발신자에 의한 서명시 사용되는 개인키와 수신자가 발신자의 서명을 사용하는 공개키 한 쌍을 갖음

 

https://server-engineer.tistory.com/586

https://rosypark.tistory.com/108

 

 

 

 

코드 설명잘해놓음

 

https://velog.io/@nara7875/BlockChain%EC%9E%91%EC%97%85%EC%A6%9D%EB%AA%85%EB%A7%88%EC%9D%B4%EB%8B%9D

728x90

+ Recent posts