DID 기반 백신접종증명서

FeelSoo·2022년 6월 10일
0
post-thumbnail

DID 기반 백신접종 증명서를 구현해보았다. DID는 이미 coov에서도 적용하고 있는 시스템이다. 그렇다면 DID는 무엇일까?

탈중앙화 신원증명(이하 DID, Decentralized Identity) 이다.

발급기관, 발급요청자, 신원증명기관, 그리고 분산원장 까지 총 4가지의 요소로 이루어진 보안 시스템이라고 할 수 있다.

발급 기관에서 요청자의 인자들을 넘겨받아 증명서를 생성하고 이를 발급자에게 1개, 발급 기관에서 관리하는 분산원장에 저장할 데이터 1개 이렇게 총 2개를 발급한 후 분산 원장에 저장되어 있는 본인의 데이터에 접근하기 위해 서는 발급 요청자가 본인의 증명서를 신원증명기관에게 검증받고 통과해야 본인의 DB에 접근이 가능하다.


이러한 시스템을 구현할 예정이다.


기능 구현 : 위에서 언급한 내용들을 토대로 풀어보면 다음과 같다

ㄱ. Credential 발급 ( 발급 기관 )

ㄴ. 발급된 Credential 저장 ( 2곳 ) ( 발급요청자, 발급기관이 저장하는 DB )

ㄷ. 두 개의 Credential이 동일한 증명서인지 검증 ( 신원검증기관 )


이 기능들을 테스트하기 위해선 우선 스마트컨트랙트 배포를 해야 한다. 코드를 리뷰하고 스마트 컨트랙트 배포부터 기능 확인까지 알아보도록 하자


https://github.com/PILSUCHOI/VaccineCredential -- 코드 저장소

테스트 네트워크 : 롭스텐

contract address : 0xa2c08eedfb7cf4f8a245d4aa5a8cd83608630458

이더스캔 url : https://ropsten.etherscan.io/tx/0xf74a5ce69cb6dc58007259aa37b68f92236f283ed70b6a3ce7596364d3faf436



** 테스터 이더 받는 주소

https://faucet.dimensions.network/

https://faucet.egorfine.com/

https://faucet.metamask.io/


코드

 //SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.10;

contract vaccineCredential {
    address private issuerAddress;                  // 컨트랙트 실행자 = 발급자
    uint256 private idCount;                        // 발급 횟수
    mapping(uint8 => string) private vaccinetype;   // 백신 종류

    struct Credential{          // 증명서에 담기는 검증 요소들
        uint256 id;             // 식별 번호
        address issuer;         // 발급자
        uint8 vaccinetype;     // 백신 종류
        string date;            // 날짜
    }

    // 발급시 저장될 위치
    mapping(address => Credential) private credentials ; // Credential 발행시 지칭될 변수
    mapping(address => Credential) private Personalmobile ; // Credential 발행시 저장될 장소1
    mapping(address => Credential) public StorageIPFS ; // Credential 발행시 저장될 장소2 ( IPFS 저장소 : 분산형 파일 시스템 저장소 )
    

    constructor() {                         
        issuerAddress = msg.sender;         // 호출자 주소를 가르키는 msg.sender
        idCount = 1;
        vaccinetype[0] = "Pfizer" ;
        vaccinetype[1] = "Moderna" ;
        vaccinetype[2] = "AstraZeneca" ;   
    }

    // Credential 발급 
    function issueCredential(address _receiverAddress, uint8 _vaccinetype, string calldata _date) public returns(bool){    // 인자 3개를 받아 새로운 증명서를 생성한다
        
        require(issuerAddress == msg.sender, "Not Issuer");
                Credential storage credential = credentials[_receiverAddress];
        
        require(credential.id == 0);
        credential.id = idCount;
        credential.issuer = msg.sender;
        credential.vaccinetype = _vaccinetype;
        credential.date = _date;

        idCount += 1;

        registerCredential(_receiverAddress);

        return true;
    }

    

    // 발급된 Credential 저장소1 ( 핸드폰 ) 
    function getCredential(address _receiverAddress) public returns(bool) {

        Credential memory mobile = credentials[_receiverAddress];
        Personalmobile[_receiverAddress] = mobile ;  
        return true;
    }


    // 발급된 Credential 저장소2 ( 분산형 시스템 저장소 ) 
    function registerCredential ( address _receiverAddress) internal {
        Credential memory IPFS = credentials[_receiverAddress];
        StorageIPFS[_receiverAddress] = IPFS ; // 저장
    }


 // Credential 판별 위한 해쉬 함수 작성
 function hash(uint256 _id, address _issuer, uint8 _vaccineType, string memory _date) pure internal returns(bytes32) {
     return keccak256(abi.encodePacked(_id,_issuer,_vaccineType,_date));
}

   
   // verify - 모바일 발급한 Credential과 IPFS에 있는 것을 대조해서 판별 
 function verifyCredential(address _receiverAddress) view public returns(bool) {

    Credential memory phoneCre = Personalmobile[_receiverAddress];
    Credential memory ipfsCre = StorageIPFS[_receiverAddress] ;      

    
    bytes32 phone = hash(phoneCre.id, phoneCre.issuer, phoneCre.vaccinetype, phoneCre.date);
    bytes32 ipfs = hash(ipfsCre.id, ipfsCre.issuer, ipfsCre.vaccinetype, ipfsCre.date);

    if(phone ==ipfs){
            return true;
        }else return false;

    }

}


contract, struct, mapping, constructor로 큰 틀, 밑구조 잡기






첫번째 기능 -- Credential 발급





두번째 기능 -- 발급된 Credential 저장 ( to mobile )




세번째 기능 -- 발급된 Credential 저장 2 ( to IPFS : 분산 저장소 )


스마트 컨트랙트 배포





좌측의 solidity compiler 탭에서 Compile을 진행한다. COMPILER 버젼에 유의하여 진행한다. ( 0.8.10+)




컴파일이 진행됬으면 Deploy 탭으로 가서 ENVIRONMENT를 injected Web3 로 변경 후 본인의 메타 마스크 계정 주소를 ACCOUT에 넣어준 후 Deploy를 진행. 이후 메타마스크에서 컨트랙트를 허용하고 얼마 안 있어 터미널에 etherscan 링크와 함께 배포가 진행될 것이다.



배포가 성공적으로 진행되었다면 이제 Credential을 발급하고 잘 저장은 되는지, 식별은 하는지를 파악하면 된다.

배포가 성공적으로 진행되었다면 Deploy 탭 좌측 하단 Deployed Contracts에 컨트랙트 관련 함수 내용들이 생성되는데 여기에 해당하는 인자들을 넣어줌으로써 제대로 작동하는지 확인할 수 있다.

< issueCredential -- 증명서 발급 >

좌측 인자 입력란에 주소(메타 계정 주소), 백신 타입 ( 0~2 중 택 1 ), 날짜를 입력하고 transact를 날리면 우측 터미널에 주소, 백신 타입, 날짜가 나오는 것을 알 수 있다.




< getCredential -- 저장 확인 ( 모바일에 저장함을 가정하는 ) >

주소를 입력하면 유효하게 저장되었는지 아닌지 값이 나온다.


< storageIPFS -- 저장 확인2 ( IPFS에 저장함을 가정하는 ) >

마찬가지로 주소를 입력하면 유효하게 저장되었는지 확인이 가능하다



< Verify -- 저장소1, 저장소2의 값이 서로 일치하는지 변경은 되지 않았는지 식별하는 기능 >

마찬가지로 주소를 입력하면 동일하면 True, 다르면 False를 뱉는데 True를 보아 이 Credential은 유효함을 알 수 있다.



회고

: 녹록치 않았다. 솔리디티 문법이 익숙치 않아 많이 절었다.

처음 진행할 때 스마트 컨트랙트 배포는 진행되었는데 Credential 가스비 이슈가 발생하며 발급이 진행이 안되었다. 또 열심히 solidty 커뮤니티를 뒤져가며 찾아봤지만 소용 없었다. 그래서 그냥 밥 먹으러 갔다.

에러 문구 : as estimation errored with the following message (see below). the transaction execution will likely fail. do you want to force sending?

밥 먹고 오니 이성을 되찾을 수 있었고 차분하게 다시 배포부터 진행하니깐 잘 되었다. 뭐가 문제였는지 정확하게 기억은 안나는데 DEPLOY ENVIRONMENT 가 injected Web3가 아니라 Javascript VM 으로 되어있어서 그랬던거 같다.

그리고 git에 commit할 생각을 못하고 다짜고짜 remix ide에다가 코드를 작성했는데 결국 로컬에다가 폴더 파고 파일을 옮긴 후에 git에 올렸다.

remix ide에서 바로 git에 올릴 수 있는 방법이 있는지 확인해봐야겠다.

솔리디티 열심히 공부해야겠다

profile
세상은 넓고 배울건 많다

0개의 댓글