사족: 다시 C++을 시작 하면서 세부적이진 않지만 기본적으로 기억해 두어야할 지침 50가지를 정리해 보았습니다. C++을 처음 시작하는 개발자들에게도 도움이 되지 않을까 싶습니다. 해당 내용 회색 글자는 팀에 의해 선택될 여기가 있다고 보는 방식입니다. 기억하기 쉽도록 경구만 썼으며 자세한 내용은 구글링과 젤 마지막 레퍼런스를 통해 확인 하시길 바랍니다.

C++ 50 계명 - 이것만은 기억하자.


일반 

1. immutable / const 은 디폴트로 적극적으로 사용한다.
2. 다형성을 가진 기본 클래스는 소멸자를 반드시 가상 소멸자로 만든다.
3. 값을 그대로 매개변수로 넣지말고, 대개 상수객체 참조자로 전달한다.
4. 변수 정의를 상단에 몰아서 하지 않는다. 사용 되는 곳 근처에서~
5. 상속보다는 합성을 사용한다. 
6. warning 을 보면 자기가 없앤다. 팀원들이 보지 않게 한다. 
7. RAAI를 항상 인식하되, 표준에서 제공해주는 것으로 되는지 확인한다.
8. C++ 은 null 포인터를 삭제해도 문제가 없다. 다만 개발시 null assert 는 많으면 많을 수록 좋다.
9. C++을 사용한다면 Class 만드는 것을 겁내지 마라. 모든것을 클래스/객체로 만든다는 생각으로 코딩한다. C++ 에서 Class는 다양한 역할을 할 수 있다. 그런게 싫다면 자바,C++  하지말고 C/Golang으로 가자. (38번참조) 
10. auto/ override /nullptr / constexpr / move / forward / atomic 키워드를 사용한다.
11. namespaces를 적극적으로 사용하며, using 은 사용하지 않는다. std:: 를 직접 붙혀준다.
12. {} 중괄호 초기화를 적극적으로 이용한다. vector<int> vec(10,20); 과 vector<int> vec{10,20}; 의 차이를 구별한다.
 initializer_list 에 대해 이해한다. 

STL

13. STL을 신뢰하고 사용한다. (개인적으론 boost 도) 
14. STL 컨테이너는 쓰레드 안전하지 않다고 각인하자.  C++11에도 여전히 쓰레드 안전한 컨테이너는 없다.( http://libcds.sourceforge.net/  이런 대체제가 있다. boost에도)
15. 많은 경우 동적으로 할당한 배열보다는 vector와 string이 낫다. (std::copy가 memcpy보다 느리지 않다)
16. 정렬이 필요 없는 맵은 C++11의 unordered_map 을 사용한다.
17. 요소를 정말로 제거하고자 한다면 remove 류의 알고리즘에는 꼭 erase를 붙여 사용하자 
18. STL 알고리즘을 적극적으로 이용한다. 

Smart Pointer

19. new / delete 를 직접하는 시대는 지났다.
20. unique_ptr 를 디폴트로 사용하자. unique_ptr로 충분하게 설계하자.
21. make_shared 로 초기화 하자.(deleter 넣어줘야 할 경우 제외) 
22. shared_ptr 나 unique_ptr 사용시 raw pointer를 별개로 생성/소멸하지 말자. 
23. 배열을 스마트 포인터로 만들었을 경우 반드시 custom deleter 를 생성자에 넣어주자.
24. shared_ptr 사용시 순환 참조가 되는지 확인하자. (weak_ptr로 해결)
25. std::move 로 스마트포인터를 이동시켜야 할 경우가 있을 때 조심 조심.
26. 위의 룰을 어겨야 할 경우가 발생시 팀원들에게 알린다.

Move vs Copy

27. 이제 move가 디폴트고 copy가 쵸이스다. 항상 연구하자. move를 사용 할 순 없는지..
28.  std::move는 원본이 없어진다는 것을 의미한다. 원본이 필요 없으면 이동하자. 

Type

29. 이왕 C++ 쓰는거 타입을 구체적으로 명시하고 타입에 안전한 코딩을 한다.
30.   int8_t, int64_t, uint32_t 와 같은 구체적 표준타입을 사용한다. 
31.  std::memcpy, std::memmove, std::memset, std::memcmp, 대신해 std::copy, std::move, std::fill, and std::equal[1] 를 사용하자.타입안정적이며 성능도 더 느리지 않으며 더 나아질 여지도 있다.

예외

32. 예외/에러는 최대한 가까운 곳에서 처리한다.(참고: 예외 처리에 대한 6가지 화두)
33.   예외를 상위 전가 시키지 말고, 리턴 값으로 처리한다. 
34.  모든 리턴 값은 에러처리로 사용한다.
35.  std::optional 을 적극적으로 이용한다.

예외처리는 너무 다양한 시각이 존재하므로 팀 설계 철학에 따라 갑니다. 개인적으로는 c/golang 방식으로 최대란 리턴값으로 가까운 곳에서 처리하는게 나은거 같습니다. 아마 예외처리에 대해 전 팀원들이 충분히 숙지/약속되어 있는 상태라면 자바처럼 복잡한/강제적인 예외 시스템을 사용하는 것도 괜찮긴 합니다만..

성능

36. 섣부른 최적화는 만원의 악 
37. 직접 메모리풀/쓰레드풀을 만드는 대신 대체제가 있는지 확인하다. 직접 만들어야 할 필요가 있을 경우 철저한 테스트가 필요하다. 
38. 인라인을 항상 고려해 본다. 
39. 아주 단순한 컨테이너/알고리즘인데 STL과 아주 큰 성능상 차이가 있으며, 그 성능이 해당 솔루션의 철학에 중요하다면 그때서야 자신의 컨테이너를 만든다.
40. 객체 생성 비용에 대한 문제가 생길 수 있다는 것만 기억하되, 최적화(BMT) 전에는 신경쓰지말아라.(9번참조)

디자인패턴/리팩토링

41. 메소드의 크기를 작게하는건 기본 중의 기본. 
42. 클래스의 책임 범위를 최소화 하며, 외부에서 로직을 주입받아 사용한다.
43. 싱글턴 패턴은 가급적 사용하지 말자. 
44. 적어도 어댑터,커맨드,전략,컴포지트,옵저버패턴은 대화가 통하게 알아두자.

동시성

45. thread 보다는 task, task 보다는 추상층 높은 아키텍터 선택(Actor, CSP)
46. 락 없는 동시성 개발을 지향한다.
47. Read/Write Lock을 선택한다.
48. 이미 존재하는 쓰레드 안전한 자료구조(컬렉션)를 사용한다. 
49. 멀티쓰레드/비동기가 무조건 빠르다는 상식을 버린다.

   예) https://hamait.tistory.com/960  https://hamait.tistory.com/839

50. 표준 병렬알고리즘을 검토한다.

결론

C++을 굳이 사용한다면 그에 걸맞는 지식을 공부하라. 로우레벨을 잘 활용 할 수 있는 수많은 지식들을 익혀야하며 그 와 동시에 OOP의 철학까지 함께 익혀야하는 정말 조심스럽게 다루어야하며 공부해야할게 많은 언어이다. 트레이드 오프를 명심하라. 필자는 C++ 경력 동안 많은 코딩과 C++서적도 20권 이상 독파했지만 대부분 다른 언어/개발 하면서 그 정수를 많이 까먹었고, 미묘한 실수를 범할 여지가 있어서 다시 체득하려면 비용이 또 따를 것이다. 따라서 애초에 이런 C++에 들이는 비용(공부비용, 수동관리에 의한 오류발생 비용,각종 타이밍 버그) 을 줄여주는 Java,Go,Rust, Python,Clojure 같은 언어를 사용하여 만들어야하는 솔루션에 집중하는 시간을 늘리는게 많은 분야에서 유리하다고 본다. 속도먹는 하마 부분만 모듈화를 한다던가. 이제 C/C++만 돌아가는 환경/C/C++에 대한 자료뿐이 없는 분야/ 0.1ms의 속도라도 줄여야하는 극한의 상황이 아니고서는 다른 언어로 눈을 돌려보는게 어떨까.



레퍼런스:

https://www.acodersjourney.com/top-10-dumb-mistakes-avoid-c-11-smart-pointers/
https://www.oreilly.com/ideas/2-major-reasons-why-modern-c-is-a-performance-beast
http://www.modernescpp.com/index.php/copy-versus-move-semantic-a-few-numbers
http://maintainablecode.logdown.com/posts/159916-memcpy-memmove-and-memset-are-deprecated
Effective C++ / Effective Modern C++ / Effective STL  / Efficient C++ 

리더피어는 조직 내에서 피어들간의 오더러로 부터 받은 블록을 공유하기 위한 대표 피어이다. 이 피어가 맛이가면 조직내의 피어들끼리 리더선출을 통해서 새로운 리더를 선출하고 오더러에 알려서 정상적으로 작동하게 된다.  

앵커피어는 조직 간의 피어들에 대한 정보 교환의 대리인으로 사용된다. 이로써 서로에 대한 위치를 알게 되어 아무 조직의 Peer 하나에 Proposal을 보내도 모두에 적용될 수 있게 되며, MSP에 대한 공유도 가능해진다. 적어도 하나의 앵키피어가 채널 설정시 정의되야하며, 채널에 참여하는 모든 피어들은 제네시스 블록안에 기록된 앵커피어에 대한 정보를 공유하게 된다.  (앵커피어가 1개일 경우 서로 다른 B,C의 조직은 A조직의 그 앵커피어를 통해서 서로에 대해 알게되고 MSP를 직접 교환하게 된다)

 

처음에 블로그를 시작했을 땐, 그저 기억보다는 글이 오래 갈꺼라는 생각에 내 공부를 저장하는 느낌으로 시작했다. 시간이 흘러...어느정도 글들이 쌓이게 되고 매우 많은 사람들이 방문하는 블로그가 되었는데, 올린 글중 틀린 내용이 생각나면 식은땀이 흐른다.. 음~~ 뻥이다. 땀은 잘 흘리지 않는 체질이다.

아무튼 뭐 블로그글이야 뭐 참고용이니깐 알아서 필터링 하거나 다른 정보와 비교,검증을 통해 개인이 알아서 판단하는게 맞는거긴 하다. 나도 남의 블로그를 볼 때는 그 정도 유도리는 가지고 참고하니깐..

그래도 최소한 책임지려는 자세는 가지려고 노력한다. 먼가 최근 글중 수정해야할 것이 떠오르면, 즉시 수정하거나 외부활동을 하는 경우엔 집/회사에 오자마자 고치고 있긴하다. (스마트폰에서는 수정이 안되서 안타깝다)

그렇더라도 시간이 흘러 내용이 바뀐 정보, 시간이 흘러 나의 생각이 바뀐 많은 것들, 내가 틀렸던 더 많은 것들에 대한 수정없이 많은 글들이 읽혀지고 있는 부분에 대해 이 자리를 빌어 죄송하다는 마음을 전하고 싶다. 

 


   


'주인장' 카테고리의 다른 글

어렸을때 즐겼던 놀이  (0) 2018.08.27
망치  (0) 2017.10.11
세방낙조  (0) 2017.06.26
2016년 여름 그리고 94년 여름의 추억  (0) 2016.08.22
안산 바위들  (0) 2016.05.06

 

어느 마을에 한 수상한 거지가 있었다.

그는 마을을 돌아다니며 각종 버려진 물건들을 주어서 자신의 비밀공터로 가지고 왔다.
공터 한구석에는 그 물건 폐품들이 산더미 처럼 쌓여 있었으며,
그 물건들은 날을 잡아서 공터 다른 구석에 있는 드럼통들에 무작정 눌러 담아 놓았다.

몇 일이 지나 거지는 어떤 마법사를 만나게 되는데 이 마법사는 폐품에서 몇가지 물건을 조합하여 
엄청난 보물을 만들 수 있는 방법을 알려 주었다. 

아무렇게나 담아져있는 드럼통에서 해당 물건을 찾기란 거의 불가능 했다. 
그래서 거지는 드럼통에 아무것이나 쑤셔 넣는게 아니라, 수 많은 폐품중에서 자신만 알고 있는 그 부품을 다른 것들과 함께 섞여져서 담을 (위장하기 위해)  드럼통을 만들어야 겠다고 생각했다.

즉 드럼통에 무엇이 들어 있는지는 다른 사람에게 들키고 싶지 않았기에 드럼통 위에 "룬조각", "성수" "에메랄드" 이런 식으로 표식 할 수는 없었다. 마법사가 또 다른 사람에게도 알려 줬을지도 모르니.. 

곰곰히 생각한 결과 만들어낸 
방식은 다음과 같다. (천재 거지?) 

드럼통 뚜껑에 그 여러가지 물건을 대표하는 표식을 해 둔다. 
대표하는 방식은 아래와 같다.  

이름이 "선풍기" 라면 획수가 16개라,  16 * o의 갯수(1) * ㅅ 의 갯수(1) = 32 이라고 써 두었다. 
이름이 "자동차 사이드미러" 라면 39 * o의 갯수(1) * ㅅ 의 갯수(1) = x 이라고 써 두었다. 
동일한 숫자의 이름이 나왔을 때는 드럼통에 추가로 적지 않고 그냥 집어 넣었다. 
이렇게 되면 하나의 드럼통에 여러가지 물건이 담겨져 있겠지~

...

어느 날 거지는 수 백개의 드럼통에서 "밥솥뚜껑" 을 찾고 싶어서 모든 드럼통을 뒤지다가..
날이 샜다. 문득 거지는 자신이 드럼통 뚜껑에 표식을 남겼다는 것을 깨닿고 ;;; (갑자기 바보?)
드럼통 뚜껑에 "밥솥뚜껑"에 대한 획수번호가 있는 드럼통을 뒤졌다.  

쉽게 찾았다. ^^v

조금의 수고  [획수번호 = '추가 계산']  및 [드럼통 위에 표식 = '추가 저장공간'] 를 한 덕분에 내부를 확인하지 않고도 
자신에 필요한 정보 위주로 모아두고 검색도 빨리 할 수 있는 드럼통을 확보 할 수 있었다.

그러던 어느날 

어느날 거지는 이번에는 "갤럭시10"을 찾아야 했다.
먼저 획수번호를 구한 후에 드럼통들의 표식을 확인하였다. 동일 한 숫자를 발견하였고 
드럼통을 확인하니 웬걸~  갤럭시 10이 없는 것이었다.?!?!

그렇다. 갤럭시10과 동일한 획수번호를 가진 놈들만 그 안에 있던 것이었다.
거지는 깨닫길

이 획수번호 체계는 드럼통안에 "갤럭시10"이 없다는 것은 100% 검증 가능하지만
"갤럭시10" 이 있다는 것은 100% 검증 할 수 없구나. 하고 탄식을 하였다..


거짓 양성(false positive) 은 실제로는 거짓인데 검사 결과는 참 이라고 나오는 것이며,
거짓 음성(false nagative) 실제로는 참인데 검사 결과는 거짓이라고 나오는 것이다. 
불룸필터는 거짓 양성기반의 확률적인 데이터 분류 체계이다. 효율적인 검색, 효율적인 분류에 사용된다.

예를 하나 더 들면 
거짓 양성(false positive) 은 부품검사장비에서 실제로는 망가진 부품인데 검사 결과는 참 이라고 나오는 것이며, 거짓 음성(false nagative) 은 부품검사장비에서 실제로는 정상인 부품인데 검사 결과는 고장이라고 나오는 것이다.
이 경우 100%정확한 장비를 만들지 못한다면 거짓음성쪽으로 발생할 확률이 높게 코딩하는게 맞다고 볼 수 있다.


P.S
비트코인의 SPV에서 볼룸필터는 왜 사용하는 걸 까요? 제 생각엔 (코드를 보고 명확히 확인하진 않았음) 

만약 내 지갑에서 네트워크상에서 발생되는 모든 트랜잭션을 전파한다고 칩시다. 그러면 일개 라이트노드인 지갑에서 너무 많은 부담을 가지게 되니깐 이건 싫습니다. 그렇다고 아무 트랜잭션도 받지 않고, 혹은 받아서 전파하지 않는 다고 합시다. 그러면 부담은 없어지지만 지갑의 존재는 무의미 하죠. 따라서 외부의 풀노드에게 나의 거래 요청(트랜잭션)만 보낸다면, 풀노드들은 내 지갑의 계정정보를 알게 됩니다. 이건 또 싫은거죠. 따라서 내 지갑에서 시작 되는 트랜잭션과 추가적으로 얼만큼의 외부에서 받아드리는 트랜잭션을 전파한다면 비교적 덜 노출 시키게 될 것입니다. 이때 외부에게 나는 이런 트랜잭션만 받겠다라고 하는데 사용되는게 블룸필터.  



 

토큰 이코노미와 토큰 디자인 패턴

본 패턴들은 블록체인에 대한 깊이 있는 분석과 공유를 하고 있는 서울대학교 디사이퍼 학회의 글을 요약,정리한 글입니다. 한번 훑어 본 후에는 해당 링크로 가서 정독하는 것을 권장합니다. 장,단점 및 더욱 자세하게 나와 있습니다. 

Means of Exchange Token 

#1. Payment 패턴 
=> 토큰을 지불 한 만큼 서비스를 제공 받음. 쿠폰을 주면 만두 서비스 추가~
=> 서비스의 성장과 토큰의 가치 성장이 연결되는 방식
=> 소비자나 공급자나 토큰을 보유하고 있을 유인이 적다.

예: golem)
분산된 컴퓨팅 자원을 P2P로 공유할 수 있게 해주는 서비스를 제공하는 분산 컴퓨팅 네트워크로써, 이용자는 토큰을 이용하여 자원을 구입하고, 제공자는 그것에 대한 보상을 받게 됩니다. 

#2. Burn and Mint 패턴 
=> 메인토큰을 서브토큰으로 환전하여 지불
=> 지불 한 만큼 서비스를 제공 받음. 쿠폰을 주면 만두 서비스 추가~ but 지불된 서브 토큰은 소각됨. 
=> 매월 새로운 메인 토큰을 정해진 숫자만큼 생성함. 
=> 토큰 유통량의 균형이 스스로 맞춰지게 됨. (이유는 레퍼런스 참고) 
=> 서비스 가격이 정해진 상태에서 수요자가 많아 질 수록 정해진 개수의 메인토큰의 가치는 높아짐.  

예: Factom)
탈중앙화 데이터 저장 솔루션을 제공하는 서비스로써 이용자는 토큰을 소각하여 데이터를 서브토큰을 통해  저장할 권리를 얻고, 블록체인에 정보를 저장하기 위해 서브토큰을 사용합니다. 제공자는 자체 블록에 데이터를 저장 한 후에 블록의 해시값을 비트코인에 저장되도록 전송합니다. 


Means of Staking

#3. Work Token패턴
=> Staking Token에서는 토큰을 사용하는 것이 아닌, 예치 되어있을 때 토큰의 가치가 토큰 보유자에게 제공됩니다.
=> Work Token 패턴은 토큰을 예치함으로써 서비스 참여자들이 네트워크를 위해서 일할 권리를 얻게 되는 토큰 시스템을 말합니다
=> 예치한 토큰의 양에 비례해서 서비스 제공자(일할 권리를 강하게 갖는)로 선정될 가능성이 커지게 됩니다.
=> 발생한 경제적인 수익을 staking한 토큰의 비율에 비례하게 가져가게 됩니다. 하지만 만약 일을 제대로 하지 못했을 경우에는 서비스 제공자는 자신이 staking한 토큰 중 일부를 몰수당하게 됩니다.
=> 일할 권리는 서비스 종류에 따라서 다양하지만 아래 예를 확인하세요.

예: AUGUR)
AUGUR는 탈중앙화된 예측 시장 및 베팅 플랫폼입니다. 이 서비스에는 시장 개설자, 베팅 참가자, 결과 판정자 세 부류의 구성원이 참여하는데, 결과 판정자는 예측 시장에 대한 결과를 판정해 주는 역할을 하게 됩니다. <- 이게 바로 일할 권리구요. 판정을 잘하면 보상을 받고, 판정을 못하면 몰수를 당하게 됩니다. 

#4.  Discount Token 패턴
=> 디스카운트 토큰이란 말 그대로, ‘특정 재화나 서비스에 대한 할인’이라는 효용을 제공해주는 토큰을 의미합니다.
=> 토큰을 예치하고 있는 사용자는 그 양에 비례하여 서비스에 대한 할인을 받을 수 있습니다. 이는 또 2종류로 나뉘는데 토큰을 사용하면서 디스카운트 받을 수도 있고, 예치한 것 만으로도 디스카운트를 받을 수 있습니다.
=> 디스카운트 토큰의 경제적 보상(재화나 서비스에 대한 할인)이 실제로 재화나 서비스를 소비했을 때만 실현되기 때문에 서비스를 사용하지 않는 토큰 홀더의 경우 손해를 볼 수 가 있습니다. 굳이 왜 홀더를..

예: Sweetbridge)
Sweetbridge는 블록체인 기반 담보 대출 플랫폼입니다. 암호화폐 등의 형태로 담보물을 맡기면 서비스의 담보대출(LTV, Loan-to-Value) 비율에 따라 스테이블 코인인 Bridgecoin을 발급해줍니다. 이후 일정 금액의 이자를 더한 Bridgecoin을 되갚으면 담보물을 찾을 수 있습니다. 담보물을 맡길 때 Sweetcoin이라는 Sweetbridge의 디스카운트 토큰을 함께 스마트 컨트렉트에 예치하면 최대 0%까지 이자율을 낮출 수 있습니다.

#5. Access token 패턴
=> Access 패턴은 사용자들이 블록체인 생태계 내의 핵심 서비스를 이용하기 위해 일정량 만큼의 토큰을 Stake해야 해당 서비스에 접근할수 있는 권한을 부여합니다. Access 토큰은 소비자가 일정 금액을 예치해야한다는 점에서 공급자가 일정 금액을 예치하는 Work 토큰과 차별성을 가집니다.

예: AirSwap)
AirSwap은 탈중앙화 거래소로써 판매자와 구매자들의 거래정보를 각각 Off-chain에 기록하고 체결된 거래만을 블록체인 상에 기록합니다.AirSwap에서 거래를 체결하려는 판매자나 구매자는 일정 금액 만큼의 AST(AirSwap Token)을 예치해야 거래 정보를 Off-Chain Order Book에 기록할 수 있습니다.

#6. Curation token 패턴 (TCR)
=> 큐레이션 서비스란 특정 회사/단체가 어떤 분야(음악 순위등)에 대해 엄선한 결과를 제공해주는 서비스를 말합니다.
=> 큐레이션 토큰은 소수가 아닌 다수의 집단 지성을 통해 큐레이션 서비스를 제공합니다.
=> TCR(Token Curation Registry): 특정 목적에 맞는 리스트(예: 맛집 리스트)를 만들고 이 리스트에 진입하고 싶은 대상들에게 신청을 받아 여러 참여자들이 검수를 한 후 진입 자격이 있다고 판단되었을 때 리스트에 포함시켜주는 방식입니다.

예: Adchain)
- Adchain은 기존 디지털 광고 시장의 문제점을 TCR을 통해 해결합니다.Adchain의 TCR 목록은 양질의 웹사이트를 모아놓은 리스트입니다.신청자는 이 리스트에 자신의 웹사이트를 추가하기 위해 먼저 100adT(예시)을 보증금으로 예치합니다. 
- 신청 후에는 일정 기간 동안 challenge period가 진행되며 토큰 홀더들은 리스트에 해당 웹사이트를 포함시킬지에 대해 심사합니다. 이때 특정 토큰 홀더가 문제가 있다고 판단할 경우, 검수자(Challenger)로서 신청자의 보증금과 동일한 금액을 베팅하고 challenge 투표를 진행합니다. 투표에는 모든 토큰 보유자들이 참여할 수 있으며 stake 양에 따라 voting power가 결정됩니다.
- 투표 결과 challenge에 성공할 경우 진입 반대에 투표한 토큰홀더들은 신청자 보증금의 절반을 stake 비율만큼 가져가게 됩니다. 검수자 역시 신청자의 보증금 절반을 받게 되고 자신의 베팅금액을 돌려받습니다. 반면 challenge가 실패할 경우 검수자가 베팅한 금액의 절반은 진입 찬성에 투표한 토큰 보유자들에게 배분되고 절반은 진입 신청자에게 돌아갑니다.

#7. Voting Token 패턴
=> 한마디로  “네트워크 의사 결정에 참여할 수 있는 토큰” 입니다.
=> 작게는 커뮤니티 글에 대한 찬성부터, 크게는 네트워크 업데이트 찬/반 투표까지 확대될 수 있습니다.
=> 네트워크의 의견을 잘 반영한 결과를 위해선, 악의적인 행동에 대해선 제약을 두어야하며, 부가적인 혜택도 주어서 voting에 많은 이용자를 참여시키는 것이 중요합니다

예: Steemit-UpVoting)
=> 스팀잇(Steemit)은 블록체인을 활용한 게시판 형태의 커뮤니티 서비스로, 글을 쓴 저자에게 페이스북의 ‘좋아요’와 같은 voting을 할 수 있습니다. Voting을 받은 저자는 그에 해당하는 보상을 네트워크 내의 토큰으로 받으며, voting을 한 독자는 큐레이션 보상을 받습니다.


사례 분석 ) 캐리 프로토콜 

 토큰 이코노미/디자인에 대한 사례로는 캐리 프로토콜을 선정하였습니다. 백서를 읽어 보았을 때 명쾌하고, 심플한 느낌은 받는 경우는 흔치 않는데요. 그 만큼 말이 되는 이야기를 하고 있으니 가능한거 같습니다. 실생활과도 매우 밀접하며 블록체인이 실생활에 적용 되고 선순환이 되는 모범 레퍼런스 사례가 우리나라에 등장한다면 이 캐리 프로토콜이 유력한 후보중 하나가 되지 않을까 하는 생각도 듭니다.

소개 

간편 포인트 적립 서비스를 이용해 성공적으로 사업을 이끌어가는 조직에서 따로 팀을 만들어 도전하는 블록체인 서비스 모델로서, 금융 비용을 줄인 탈중앙화 토큰 이코노미 모델을 이용하여 오프라인 매장소비자에게 보다 유리한 혜택을 주기 위한 서비스. 거대한 자본이 거래되는 것이 아니라 포인트 기반으로 일반 대중들에 의해 편리하게 사용되는 것을 목표를 두는 만큼(향후는 어떻게 될 런지 모르겠다) 트랜잭션 비용이라든지, 블록체인의 삼각 코너중 하나를 이루는 탈중앙,보안쪽을 조금 약화시킬 수 있어서 성능을 기존 도도포인트의 트랜잭션만큼 높일 수 있으리라 본다. (이 부분은 물론 플랫폼 종속적인데  이더리움 메인넷에서는 힘들고, 서브체인을 구축하여 야 할 것으로 보인다. 직접 구현하려면 loom 네트워크같이 플라즈마 캐쉬등의 구현이 필요할거 같다.) 비교적 합리적인 프로젝트이기에 앞으로 지켜 볼 만한 하며, 좋은 레퍼런스가 되어 주었으면 한다. 

주요구성원

주요 참여자 

소비자 : 데이터를 기부하고 보상을 받는다. 광고를 소비하고 보상을 받는다. 포인트를 소비한다.
매장: 데이터를 소비자에게 돌려준다. 소비자에게 광고를 한다. 포인트를 발급한다.
광고주: 데이터를 소비(분석)하여 광고를 한다. 분석은 주로 광고대행사가 할 것이다.

부가 사업자

정산사업자: 토큰을 법정화폐와 교환 해준다. 정산수수료등으로 수익을 얻을 수 있다.
광고대행자: 광고주를 대신해서 광고 대상에 대한 데이터분석을 하여 적절한 대상에게 광고를 할 수 있게 한다.
단말기사업자: 매장내에 단말기를 설치하여 준다. 단말기 사용에 따른 수수료등으로 수익을 얻을 수있다.
지갑사업자: 소비자에게 지갑앱을 제공한다. 지갑앱으로는 1) 소비자가 자신의 결제 데이터 관리하고 블록체인에 올려서 보상을 받을 수 있도록 도와주는 것, 2) 일반 가상화폐(BTC, ETH 등) 및 캐리 프로토콜 상의 가상화폐(CRE, BT)를 보유하고 사용할 수 있게 해주는 것, 3) 광고를 보여주는 매체로서의 기능을 담당한다. 

토큰 이코노미

캐리프로토콜의 토큰디자인 패턴은 payment 패턴 + Work Token패턴으로 볼 수 있으며 브랜드토큰(BT)을 이용하여 서비스(커피한잔등)을 얻을 수 있고, CRE의 사용 및 예치로 광고를 할 수 있으며, BT도 만들수 있다. 추후에는 토큰홀딩을 위한 discount패턴 및 탈중앙화의 장점을 살린 voting패턴을 추가 할 만한 여지가 있다. 매장,광고주 등등이  예치를 통해서 서비스를 하기 때문에 홀딩역할을 하는듯 보이나, 백서기준 40%에 해당하는 서포터에 대한 토큰은 어떻게 홀딩되는건지정확히 모르겠지만 네트워크가 발전하는 상황하에 증권형 수익모델을 제공하는 것으로 보인다.


주저리 주저리 

주요 사항
)
- 정산사업자와 함께하는것에 감명. 거래소를 직접통하라는 것은 말이 안됨. 따라서  매장업주들이 편할듯. 그런데 정난수수료는 ? 초기에 부담? 추후에는 클레이튼,카카오뱅크와 연합하면 좋을듯.
- 어떤 플랫폼에서 서비스를 할런지? 그 플랫폼의 성공 여부 (주로 확장성 이슈에 관한)  클레이튼이 잘 만들어졌으면..
- 블록체인을 안 할 때와 비교해 금융,신뢰비용이 얼마나 감소될런지에 대한 조사가 있나.
- 직접 경제에 참여치 않는 서포터가 40%를 가지고 있는데 토큰홀더 유지책은?

기타사항)
- 사용자와 매장관리자를 어떻게 기존 도도포인트와 차별화하여 감명받게 할 것인지
- 선택된 플랫폼에 대한 어떤 기여를 할 것인지? 플랫폼에 대한 직접 개발을 서브로 할 계획은 없는지?
- 토큰명을 더 친근하게 바꾸면 좋겠다. 토큰이라는 이름 자체도 사용하면 안되며 CRE같은 이름은 한국은행에서나 사용 할 만함. 도도포인트와 퐁당포인트. 1퐁당 10퐁당 ~ 
- 사용자가 블록체인을 사용하는지 모르게 매우 심플하게 하는건 좋은데 뭔가 탈중앙화라는 요소에 대한 냄새도 풍겨야 하는게 아닌가 싶다.따라서 블록체인의 기계적인 냄새는 없애되, voting같은 것을 통해 자신도 새로운 민주적인 세상에 참여한다는주인의식을 심어 주는 서비스. 물론 당장은 아니다. 
- 유튜브를 통한 15초내의 붐업영상
- 브랜드 토큰간 동맹 프로토콜 추가 
- 디스카운트 프로토콜 추가 



레퍼런스:
캐리프로토콜 백서 
토큰이코노미패턴분류 by 디사이퍼   



하이퍼레저 패브릭 MSP 

MSP는 하이퍼레저 패브릭에서 각 피어와 사용자에 대한 인증/인가 작업에 대한 추상층입니다. 퍼블릭 블록체인과는 다른 콘소시엄 블록체인에서만 복잡하게 존재하는 모듈로써,  구현하는거 자체도 PKI의 복잡성을 그대로 물려받기 때문에 복잡하지만 실제 콘소시엄 블록체인을 구축하여 조직들간의 거버넌스 정책을 만들어 나가는 프로세스는 더욱 더 복잡하지 않을 까 싶습니다. 즉 새로운 조직을 어떻게 추가시키는지 같은? 현재 대부분의 패브릭 프로젝트에서 설립자 주도적 네트워크 구성을 하고 있는것으로 아는데 (즉 조직간 합의가 필요없음. 그냥 짱이 알아서 하는?) 진짜 조직별로 권한이 균등이 나누어져 있는 네트워크에서의 실제 사용사례에 대한 레퍼런스에 대한 공개가 기대됩니다.

이 글에서는 하이퍼레저 패브릭에서 사용되는 MSP를 간단하게 피어계열인증서/사용자계열인증서 기반의 트랜잭션을 일으키고 오더러에서 확인하는 과정을 코드로써 살펴 볼 것입니다.  

하이퍼레저 패브릭에서 암호화 재료 만들기 

하이퍼레저 패브릭에서는 3가지 방식중 선택하여 암호화 재료를 만들 수 있습니다.

1. OpenSSL을 이용하여 (테스팅) 
2. CryptoGen 유틸리티를 이용하여 (테스팅)
3. Fabric-CA 서비스를 이용하여  (프로덕트)

심플 MSP를 만들어보기


진행중..

MSP는 하이퍼레저 패브릭에서 각 피어와 사용자에 대한 인증/인가 작업에 대한 추상층입니다. 퍼블릭 블록체인과는 다른 콘소시엄 블록체인에서만 복잡하게 존재하는 모듈로써,  구현하는거 자체도 PKI의 복잡성을 그대로 물려받기 때문에 복잡하지만 실제 콘소시엄 블록체인을 구축하여 조직들간의 거버넌스 정책을 만들어 나가는 프로세스는 더욱 더 복잡하지 않을 까 싶습니다. 즉 새로운 조직을 어떻게 추가시키는지 같은? 현재 대부분의 패브릭 프로젝트에서 설립자 주도적 네트워크 구성을 하고 있는것으로 아는데 (즉 조직간 합의가 필요없음. 그냥 짱이 알아서 하는?) 진짜 조직별로 권한이 균등이 나누어져 있는 네트워크에서의 실제 사용사례에 대한 레퍼런스에 대한 공개가 기대됩니다.

이 글에서는 하이퍼레저 패브릭에서 사용되는 MSP를 간단하게 구현해보는 시간을 갖으려 합니다. 해싱/암호화/PKI 등에 대한 기본지식은 알고 있다고 가정하며(사실 읽으면서 찾아보면 됩니다) 첫번째로는 각 기술에 대한 코딩 지식 기반과 무엇을 할 수 있는지에 대한 감을 잡고, 후에는 실제 하이퍼레저패브릭 심플 시뮬레이션을 만들어서 피어계열인증서/사용자계열인 증서 기반의 트랜잭션을 일으키고 오더러에서 확인하는 과정을 코드로써 살펴 볼 것 입니다.  

Go언어의 Crypto라이브러리 

go 언어가 지원하는 표준 라이브러리들 입니다. 이를 이용한 여러가지 암호화 관련 된 코드는 더 아래에서 살펴보죠. 

aes : Package aes implements AES encryption (formerly Rijndael), as defined in U.S. Federal Information Processing Standards Publication 197.
cipher:  Package cipher implements standard block cipher modes that can be wrapped around low-level block cipher implementations.
des: Package des implements the Data Encryption Standard (DES) and the Triple Data Encryption Algorithm (TDEA) as defined in U.S. Federal Information Processing Standards Publication 46-3.
dsa: Package dsa implements the Digital Signature Algorithm, as defined in FIPS 186-3.
ecdsa: Package ecdsa implements the Elliptic Curve Digital Signature Algorithm, as defined in FIPS 186-3.
elliptic: Package elliptic implements several standard elliptic curves over prime fields.
hmac: Package hmac implements the Keyed-Hash Message Authentication Code (HMAC) as defined in U.S. Federal Information Processing Standards Publication 198.
md5: Package md5 implements the MD5 hash algorithm as defined in RFC 1321.
rand: Package rand implements a cryptographically secure pseudorandom number generator.
rc4: Package rc4 implements RC4 encryption, as defined in Bruce Schneier’s Applied Cryptography.
rsa: Package rsa implements RSA encryption as specified in PKCS#1.
sha1: Package sha1 implements the SHA1 hash algorithm as defined in RFC 3174.
sha256: Package sha256 implements the SHA224 and SHA256 hash algorithms as defined in FIPS 180-4.
sha512: Package sha512 implements the SHA-384, SHA-512, SHA-512/224, and SHA-512/256 hash algorithms as defined in FIPS 180-4.
subtle: Package subtle implements functions that are often useful in cryptographic code but require careful thought to use correctly.
tls: Package tls partially implements TLS 1.2, as specified in RFC 5246.
x509: Package x509 parses X.509-encoded keys and certificates.
pkix: Package pkix contains shared, low level structures used for ASN.1 parsing and serialization of X.509 certificates, CRL and OCSP. 

X.509 인증서 구조 

자신의 공개키를 인증 받기 위해 CA의 비밀키를 이용해서 만든 CA서명증서입니다.검증은 CA셀프인증서를 통해서 할 수 있습니다. 구체적으로는 CA(or Intermediate CA) 공개키로 위의 그림에서 서명알고리즘으로 복호화 한것과 서명이 일치하면 OK란거죠. 서명알고리즘에는 RSA계열과 ECDSA계열이 있습니다.


Go언어를 이용한 암호화 코딩 예제 

0. HMAC 을 이용한 메세지 해싱 

HMAC:  hash message authentication code  즉 해싱에 의한 메세지 검증/인증으로 비밀키에 의해  -> 해싱은 되나  <- 반대 방향의 복구는 불가능한 , 즉 한방향으로만 작동하기 때문에 보통 확인 용도(보낸 내용이 무엇인지가 아니라, 보낸 내용이 보낼 때와 변경되진 않았는지 or 이미 저장되어 있는 정보와 일치하는지) 로 사용됩니다. 또한해싱의 특성상 원래의 것 보다 더 짧은 길이의 값이나 키로 변환해서 이득을 얻을 수 있는 많은 곳에 사용됩니다.

"crypto/hmac"
"crypto/sha256"
"crypto/sha512"


func main() {
message := "Today web engineering has modern apps ..."
salt := generateSalt()
fmt.Println("Message: " + message)
fmt.Println("\nSalt: " + salt)

hash := hmac.New(sha256.New, []byte(secretKey))
io.WriteString(hash, message+salt)
fmt.Printf("\nHMAC-Sha256: %x", hash.Sum(nil))

hash = hmac.New(sha512.New, []byte(secretKey))
io.WriteString(hash, message+salt)
fmt.Printf("\n\nHMAC-sha512: %x", hash.Sum(nil))
}


1. AES 대칭키를 이용한 암호화/복호화 

서로 공유하고 있는 동일한 키(대칭키라고 함)로 암호화하고 복호화 하는 방식에 관한 코드입니다.

"crypto/aes"


func encrypt(key []byte, text string) (string, error) {
block, err := aes.NewCipher(key)
cfb := cipher.NewCFBEncrypter(block, iv)
... }

func decrypt(key []byte, text string) (string, error) {
block, err := aes.NewCipher(key)
cfb := cipher.NewCFBDecrypter(block, iv)
...
}


2. RSA 개인키/공개키 생성

 RSA 기반의 개인키와 공개키를 생성합니다. 대칭키와 다르게 2가지의 키가 생성됩니다.


rsaPriKey, rsaPubKey := GenerateKeyPair(1024) // 개인키와 공개키 쌍 생성


3. PEM EXPORT / IMPORT 

 개인키,공개키 혹은 인증서등을 pem 파일로 export/import 할 수 있습니다.여기서는 확장자를 pem으로 하였지만 crt (인증서) , key (개인키) 등으로 할 수도 있습니다.
func main(){

   // GENERATE
   privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
   publicKey := &privateKey.PublicKey

   // WRITE to pem file 
   pemPrivateFile, err := os.Create("private_key.pem")
   if err != nil {
      fmt.Println(err)
      os.Exit(1)
   }

   var pemPrivateBlock = &pem.Block{
      Type:  "RSA PRIVATE KEY",
      Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
   }

   err = pem.Encode(pemPrivateFile, pemPrivateBlock)
   if err != nil {
      fmt.Println(err)
      os.Exit(1)
   }
   pemPrivateFile.Close()

   // READ From pem file 
   privateKeyFile, err := os.Open("private_key.pem")
   if err != nil {
      fmt.Println(err)
      os.Exit(1)
   }

   pemfileinfo, _ := privateKeyFile.Stat()
   size := pemfileinfo.Size()
   pembytes := make([]byte, size)
   buffer := bufio.NewReader(privateKeyFile)
   _, err = buffer.Read(pembytes)
   data, _ := pem.Decode([]byte(pembytes))
   privateKeyFile.Close()

   privateKeyImported, err := x509.ParsePKCS1PrivateKey(data.Bytes)
  
}


4. RSA 암호화/복호화

 hello를 공개키로 암호화하고, 개인키로 복호화 합니다. (키쌍을 암호화에 사용) 

////////// Encrypt / Decrypt ///////

rsaPriKey, rsaPubKey := GenerateKeyPair(1024)  // 개인키와 공개키 쌍 생성

encryptedMsg := EncryptWithPublicKey([] byte ("hello"), rsaPubKey2 ) // 공개키로 암호화
decryptedMsg := DecryptWithPrivateKey(encryptedMsg, rsaPriKey2) // 개인키로 복호화 


5. RSA 서명/확인

 hello를 개인키로 서명하고, 공개키로 확인 합니다. (키 쌍을 서명을 위해 사용 + 자기부인 방지)

////////// Sign / Verify  ////////////

alicePrivateKey, err := rsa.GenerateKey(rand.Reader, 2048) // 개인키와 공개키 쌍 생성 
alicePublicKey := alicePrivateKey.PublicKey

secretMessage := "Hello 8gwifi.org"

signature := SignPKCS1v15(secretMessage,*alicePrivateKey) // 개인키로 서명  
verif := VerifyPKCS1v15(signature, secretMessage,  alicePublicKey ) // 공개키로 확인 


6. ECDSA 개인키/공개키 생성 

 하이퍼레즈 패브릭이나 이더리움에서는 RSA 말고 ECDSA를 사용합니다.

pubkeyCurve := elliptic.P256() //see http://golang.org/pkg/crypto/elliptic/#P256

privatekey := new(ecdsa.PrivateKey)
privatekey, err := ecdsa.GenerateKey(pubkeyCurve, rand.Reader)

if err != nil {
   fmt.Println(err)
   os.Exit(1)
}

var pubkey ecdsa.PublicKey
pubkey = privatekey.PublicKey


7. ECDSA 서명/확인

RSA에서와 마찬가지로 서명/확인에 사용 할 수 있습니다.
pubkeyCurve := elliptic.P256() //see http://golang.org/pkg/crypto/elliptic/#P256

privatekey := new(ecdsa.PrivateKey)
privatekey, err := ecdsa.GenerateKey(pubkeyCurve, rand.Reader) 

var pubkey ecdsa.PublicKey
pubkey = privatekey.PublicKey

// Sign ecdsa style
var h hash.Hash
h = md5.New()
r := big.NewInt(0)
s := big.NewInt(0)

io.WriteString(h, "This is a message to be signed and verified by ECDSA!")
signhash := h.Sum(nil)

r, s, serr := ecdsa.Sign(rand.Reader, privatekey, signhash)

signature := r.Bytes()
signature = append(signature, s.Bytes()...)

// Verify
verifystatus := ecdsa.Verify(&pubkey, signhash, r, s)
fmt.Println(verifystatus) 


8. ECDH 로 (비밀키 전송없이) 비밀키 공유하기

간단히 말해서 나의 비밀키 * 상대방의 공개키 == 상대방의 비밀키 * 나의 공개키 라는 등식을 이용해서, 공통의 비밀키를 갖는 방식입니다. 이더리움에서는 피어끼리 접속 할 때마다 임시의 공개키/개인키를 만들어서 (참고로 임시가 아닌 static 공개키는 바로 자신의 주소죠) ECDH를 이용하여 만든 비밀키로 RLP인코딩한 패킷을 암호화하여 송/수신합니다. 
var privKey1, privKey2 crypto.PrivateKey
var pubKey1, pubKey2 crypto.PublicKey

var err error
var ok bool
var secret1, secret2 []byte

privKey1, pubKey1, err = e.GenerateKey(rand.Reader)
privKey2, pubKey2, err = e.GenerateKey(rand.Reader)


secret1, err = e.GenerateSharedSecret(privKey1, pubKey2)
secret2, err = e.GenerateSharedSecret(privKey2, pubKey1)

if !bytes.Equal(secret1, secret2) {
   log.Print("The two shared keys: %d, %d do not match", secret1, secret2)
}


9. PKI 시스템 (CA생성,서명하기,서명 확인하기) 


웹서비스 회사에서 https 서비스를 하기 위해 Verisign, Comodo, Thawte, GeoTrust, GlobalSign 같은 CA로 부터 자신의 공개키를 그들의 개인키로 서명한 인증서(. X.509)를 받아서 사용합니다. 이렇게 CA를 통하여 인증을 받은 공개키를 통해 신원을 검증하고 비밀키 교환을 하는 일련의 과정에 인프라를 PKI라고 합니다. 

하이퍼레저 패브릭 같은 콘소시엄형 블록체인은 각 조직에 대한 허가/인증이 중요한 기능이기에 이런 PKI를 시스템내에 직접 구현하여 활용합니다. 먼가 복잡해 보이지만  개인키,공개키 만드는 로직/인증서 만드는 로직/ 인증서 검증하는 로직만 있으면 만들 수 있습니다. 
- CA 자가서명 (CA는 루트이므로 자기 스스로 서명하게 됩니다.)
func main() {
   ca := &x509.Certificate{
      SerialNumber: big.NewInt(1653),
      Subject: pkix.Name{
         Organization:  []string{"ORGANIZATION_NAME"},
         Country:       []string{"COUNTRY_CODE"},
         Province:      []string{"PROVINCE"},
         Locality:      []string{"CITY"},
         StreetAddress: []string{"ADDRESS"},
         PostalCode:    []string{"POSTAL_CODE"},
      },
      NotBefore:             time.Now(),
      NotAfter:              time.Now().AddDate(10, 0, 0),
      IsCA:                  true,
      ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
      KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
      BasicConstraintsValid: true,
   }


   privateKey, _ := ecdsa.GenerateKey(elliptic.P384(), rand.Reader) // ecdsa.PrivateKey
   publicKey := &privateKey.PublicKey // ecdsa.PublicKey

   ca_b, err := x509.CreateCertificate(rand.Reader, ca, ca, publicKey, privateKey)

   if err != nil {
      log.Println("create ca failed", err)
      return
   }

   // Public key
   certOut, err := os.Create("ca.crt")
   pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: ca_b})
   certOut.Close()
   log.Print("written cert.pem\n")

   // Private key
   keyOut, err := os.OpenFile("ca.key", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
   x509Encoded, _ := x509.MarshalECPrivateKey(privateKey)
   pem.Encode(keyOut, &pem.Block{Type: "ECDSA PRIVATE KEY", Bytes: x509Encoded})
   keyOut.Close()
   log.Print("written key.pem\n")
}

- CA를 이용한 개인 인증서 생성 및 확인 (개인들은 자신의 공개키/개인키를 만든 후에 공개키를 CA의 개인키를 이용하여 서명하고 X.509구조의 인증서를 만들게 됩니다) 
package main

import (
   "bufio"
   "crypto/ecdsa"
   "crypto/elliptic"
   "crypto/rand"
   "crypto/tls"
   "crypto/x509"
   "crypto/x509/pkix"
   "encoding/pem"
   "fmt"
   "log"
   "math/big"
   "os"
   "time"
)

func main() {

   // Load CA
   catls, err := tls.LoadX509KeyPair("ca.crt", "ca.key")
   if err != nil {
      panic(err)
   }
   ca, err := x509.ParseCertificate(catls.Certificate[0])
   if err != nil {
      panic(err)
   }

   cert := &x509.Certificate{
      SerialNumber: big.NewInt(1653),
      Subject: pkix.Name{
         Organization:  []string{"ORGANIZATION_NAME"},
         Country:       []string{"COUNTRY_CODE"},
         Province:      []string{"PROVINCE"},
         Locality:      []string{"CITY"},
         StreetAddress: []string{"ADDRESS"},
         PostalCode:    []string{"POSTAL_CODE"},
      },
      NotBefore:             time.Now(),
      NotAfter:              time.Now().AddDate(10, 0, 0),
      IsCA:                  true,
      ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
      KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
      BasicConstraintsValid: true,
   }


   privateKey, _ := ecdsa.GenerateKey(elliptic.P384(), rand.Reader) // ecdsa.PrivateKey
   publicKey := &privateKey.PublicKey // ecdsa.PublicKey

   cert_b, err := x509.CreateCertificate(rand.Reader, ca, ca, publicKey, privateKey)

   if err != nil {
      log.Println("create ca failed", err)
      return
   }

   // Public key
   certOut, err := os.Create("bob.crt")
   pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: cert_b})
   certOut.Close()
   log.Print("written cert.pem\n")

   // Private key
   keyOut, err := os.OpenFile("bob.key", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
   x509Encoded, _ := x509.MarshalECPrivateKey(privateKey)
   pem.Encode(keyOut, &pem.Block{Type: "ECDSA PRIVATE KEY", Bytes: x509Encoded})
   keyOut.Close()
   log.Print("written key.pem\n")


   // get pubic key from certificate
   cert, _ = x509.ParseCertificate(cert_b)
   ecdsaPublicKey := cert.PublicKey.(*ecdsa.PublicKey)
   log.Print(ecdsaPublicKey)

   // get pubic key from certificate pem file
   certFile, err := os.Open("bob.crt")
   if err != nil {
      fmt.Println(err)
      os.Exit(1)
   }

   pemfileinfo, _ := certFile.Stat()
   size := pemfileinfo.Size()
   pembytes := make([]byte, size)
   buffer := bufio.NewReader(certFile)
   _, err = buffer.Read(pembytes)
   data, _ := pem.Decode([]byte(pembytes))
   certFile.Close()


   cert2, _ := x509.ParseCertificate(data.Bytes)
   ecdsaPublicKey2 := cert2.PublicKey.(*ecdsa.PublicKey)
   log.Print(ecdsaPublicKey2)

   // certificate validation
   checkSign:= cert2.CheckSignatureFrom(ca)
   if checkSign == nil {
      log.Print("check ok")
   }

}

위 예제들의 완전한 코드는 이런 예제를 이용하여 하이퍼레저 패브릭 MSP를 시뮬레이션 해보는 작업과 함께 다음 글에서 MSP 코드와 함께 Github에 올릴 예정입니다. 


다음 글: 400라인의 go코드로 구현한 하이퍼레저 패브릭 [4-1]-  MSP (2) (작성중..) 




레퍼런스:

https://fale.io/blog/2017/06/05/create-a-pki-in-golang/ 
https://8gwifi.org/docs/go-rsa.jsp 
https://github.com/hyperledger/fabric/blob/release-1.4/common/tools/cryptogen/main.go 
https://github.com/ethereum/go-ethereum/tree/master/p2p 
https://github.com/hyperledger/fabric/tree/release-1.4/msp 



+ Recent posts