블록체인을 더 은행처럼 만들기

Luke Park
D3LAB
13 min readApr 1, 2022

--

페이스북에서 연구한 키 유실에 대한 사후 복구 방안

Blackshear, Sam, et al. “Reactive Key-Loss Protection in Blockchains.” International Conference on Financial Cryptography and Data Security. Springer, Berlin, Heidelberg, 2021.

블록체인에서 키를 분실하거나 잘못된 주소로 자산을 보내 영구히 분실하는 경우가 종종 발생한다. 사실, 꽤 많이 발생한다. 2018년의 한 분석에 따르면 5백만 블록 높이 이전에 적어도 12,000 개의 이더(ETH)가 오타로 인한 영구적 손실의 희생양이 되었다[1].

물론… 사람의 실수뿐만 아니라 소프트웨어 버그(클라이언트 단의 실수)로도 이런 일이 일어날 수 있으니 이러한 대참사는 생각보다 여러분 가까이에 있을지도 모른다.

그러나 블록체인은 현실의 은행과는 달리 이런 상황에서 사후 복구할 수 있는 방법이 없다. 그도 그럴 것이, 개인키를 모르면 그 계좌의 자산을 운용할 수 있는 방법이 전혀 없기 때문이다.

기존의 방법들

다음은 실수를 줄이거나 대응하기 위해 고안 및 적용되던 기존의 방법들이다.

잘못 입력된 주소

  • Checksum: 주소에 체크섬을 추가해 단순한 오타를 방지한다.
  • QR 코드 사용: QR 코드는 리드솔로몬 에러 정정이 내장되어 있으므로 복사-붙여넣기 과정에서의 실수를 줄일 수 있다.
  • 주소 생성: 계좌 기반 블록체인인 Diem은 계좌를 생성하는 트랜잭션이 별도로 존재한다. 이는 계좌를 먼저 개설하고 나서야 입출금 양방향 거래가 가능한 전통적 은행 시스템과도 유사하다. 개설되지 않은 계좌에 대한 코인 전송은 거절되기에, 주소를 오타 내는 간단한 실수를 방지할 수 있다.

개인키 유실

사실 블록체인에서 개인키를 잃어버리는 것은 현실에서 자아를 잃어버리는 것과 같으니, 조심 또 조심해서 보관하는 수밖에 없다. 그럼에도 불구하고 타의적으로 개인키가 유실되는 경우가 있으니:

  • 장비의 고장
  • 전쟁 및 천재지변
  • 심지어는 가족의 실종 또는 사망으로 인한 유실도 종종 일어나며, 앞으로 더 빈번히 일어날 일이 될 것이다.

이런 경우를 대비할 수 있는 종래의 기법들은 다음과 같다:

  • 안전하게 오프라인으로 관리되는 HSM (Hardware Security Module)
  • 커스터디 서비스 (custodial services) 혹은 프라이빗 키 복구 권한이 있는 가디언즈(guardians) 설정 (EIP55)
  • 분산된 키: Shamir’s secret sharing과 같은 기법을 사용
  • M-of-N 멀티시그: 적어도 N명 중 M명의 서명이 있어야지만 트랜잭션이 유효. 서명 검증의 양이 늘어나기 때문에 트랜잭션 처리가 더 비싸질 수 있음.
  • 결정론적 키 생성: BIP32 제안처럼 하나의 마스터 시드(master seed)로부터 다른 계좌 키들이 결정론적으로 도출됨. 마스터 시드 하나만을 보관 및 암호화하여 관리하면 됨.
  • 볼트(vault) 트랜잭션: 출력을 일정 기간동안 잠금하는 특별한 트랜잭션 타입. 잠긴 이 기간 동안 적법한 계좌는 두 번째 복구 키를 이용해 취소가 가능하다. 보통 두 번째 복구 키를 오프라인 HSM 등을 이용해 안전히 보관한다.

그러나 이런 방법들은 참사가 일어나기 전에 사전에 예방 조치를 취해두어야지만 복구가 가능했다. 또한 마치 보험과도 같아, 이용자는 혹시 모를 사고에 지속적으로 비용을 지출해야만 한다는 단점이 있다.

그렇다면 사후 처리가 가능한 복구 방법론이 있을까?

KELP 프로토콜

본 논문의 저자들은 알려진 지식 하에서는 최초로 사후 복구 방안을 제시한다. 키가 유실되거나 잘못된 주소로 전송된 자산은 아무도 접근할 수 없는 상태가 되는데, 이를 달리 말하자면 해당 주소에 대한 개인키를 아무도 모른다는 말과 같다. 이 점을 이용해 임의 주소에 대해서 자산 소유권을 주장할 수 있게 했다. 만일 일정 기간 동안 아무도 주장에 대한 반박, 즉 개인키로 서명한 메시지를 만들지 못하면, 자산을 소유하게 된다.

물론 이 방법을 나이브하게 구현하면 여러 공격 요소들이 존재한다.

  • 프론트러닝(Front-running): 채굴자나 풀노드를 운영하는 공격자는 대기(pending) 상태에 있는 주장(claim) 트랜잭션을 미리 살펴보고, 적법하지 않음에도 불구하고 자신이 먼저 주장 트랜잭션을 보낼 수 있다.
  • 랜덤 테스팅(Random testing): 주장 트랜잭션을 계좌 소유주만이 보낼 수 있는 것이 아니므로, 공격자가 랜덤하게 많은 수의 계좌에 대해 주장할 수 있다.

이를 완화하고 방어하기 위해 본 논문에서는 (1) 주장을 숨기는 Commit, (2) 주장을 공개하는 Reveal, 마지막으로 (3) 자산을 주장해 가져오는 Claim 혹은 자산을 방어하는 Challenge의 3단계 구조를 제안한다.

KELP 흐름도

출처: Blackshear, Sam, et al. “Reactive Key-Loss Protection in Blockchains.” International Conference on Financial Cryptography and Data Security. Springer, Berlin, Heidelberg, 2021.

KELP.Commit

KELP.Commit(address_c, address_r, nonce) → com, fee_1

KELP.Commit은 address_c의 소유권을 주장하는 누구나 호출할 수 있다. 정상적인 상황이라면 개인키를 유실했거나 잊어버렸을 경우, 혹은 잘못된 주소로 전송해 해당 주소의 개인키를 모르는 경우에 해당할 것이다. Commit의 출력은 커미트먼트 값인 com = h(address_c || address_r || nonce)에 해당하며, 이 값이 블록체인에 기록된다.

이러한 커미트먼트 스킴은 어떠한 정보를 우선 기록 및 공유하고 추후에 공개하기 위해 사용된다. address_c와 address_r에 대한 정보가 블록체인에 기록되면서도 정보가 숨겨지기 때문에 프론트러닝을 할 수 없다. 더불어 추가적인 nonce 값을 포함함으로써 무작위 대입법으로 address들에 대한 정보를 얻지 못하도록 한다.

이 커미트먼트가 블록체인에 담길 때, 프로토콜은 트랜잭션 발행자로부터 fee_1을 지불하도록 한다. 이 fee_1은 채굴자나 검증자가 가져가는, 블록체인 트랜잭션을 발행할 때 쓰이는 수수료와는 별개이다. 이는 랜덤 테스팅 공격을 방지하기 위한 비용이며, 악의적인 사용자가 아닌 이상 추후에 다시 회수할 수 있다.

KELP.Reveal

KELP.Reveal(com) → address_c, address_r, nonce, fee_2

KELP.Reveal은 이전에 Commit 트랜잭션을 보냈던 사용자가 이후에 수행할 수 있는/수행할 트랜잭션이다. 이 트랜잭션의 역할은 커미트먼트가 무엇인지를 밝히는 것으로, address들의 정보와 무작위 값이 드러나게 된다.

이제 적법한 계좌 소유자는 자신의 계좌가 주장 당할 것임을 파악할 수 있게 되고, 그렇기에 챌린지를 걸 수도 있다. 따라서 이 다음 단계는 주장(claim) 또는 챌린지(challenge)로 이어진다.

공개된 주장을 받아들이기 이전에, KELP 컨트랙트는 다음과 같은 사항들을 체크한다:

  • h(address_c || address_r || nonce)는 Commit 트랜잭션에서 제시했던 com 값과 동일해야 한다.
  • timeof(Reveal) - timeof(Commit) < t_1 이어야 한다. timeof()는 트랜잭션이 블록체인에 포함된 타임스탬프나 블록 높이 등의 시간 단위를 반환하는 함수이다.
  • 충분한 수수료 fee_2가 트랜잭션에 포함되어야 한다. fee_2는 악의적 사용자의 공격 비용을 높이는 역할을 한다.

이 단계는 아직 계좌 소유권이 넘어간 상태가 아니며, 다음 단계에서 Claim이 실제로 수행되어야지만 이전된다.

KELP.Claim

KELP.Claim(address_c, address_r, nonce) → com

KELP.Claim은 실질적으로 address_c의 소유권을 address_r로 넘기는 트랜잭션이다. 컨트랙트는 다음 조건들을 체크하고 이 트랜잭션을 수용하는데:

  • com 커미트먼트가 address_c에 대한 활성화된 주장에 대응되어야 하고
  • timeof(Claim) — timeof(Reveal) >t_2 이어야 한다. 이는 주장이 등장하고 난 이후 충분한 시간이 지나 챌린지 기간이 끝나야 함을 의미한다.

소유권 이전의 구체적인 방법은 블록체인 프로토콜마다 다르지만, 어떠한 형태로든 자산을 복구하면 된다.

이때 수수료 fee_1과 fee_2를 address_c의 잔액과 함께 가져갈 수 있으므로(실제로는 Reveal 단계에서 이미 address_c의 잔액으로 더해진다) 주장에 소요되는 비용은 크게 상관이 없다. 즉, 성공적인 주장 수행은 수수료들을 환급받는 과정에도 해당된다.

KELP.Challenge

KELP.Challenge(address_c, signature_c) → cancel_claim

KELP.Challenge는 address_c의 소유주가 부정한 주장으로부터 자신의 돈을 지키기 위해 호출된다. 이 트랜잭션은 자신이 소유하고 있다는 증빙을 담아야 하므로 개인키로부터 만들어지는 서명 signature_c를 포함한다.

유효한 Challenge는 즉각적으로 잠재적 주장을 취소하게 되고, 수수료 fee_1과 fee_2를 회수하게 된다. (사실 Reveal 단계에서 이미 fee_1과 fee_2가 잔액에 더해져 있으면 그냥 다른 주소로 전송해버리면 된다)

만일 fee_1과 fee_2의 합이 크다면 공격 비용이 매우 클 것이며, 이는 곧 프로토콜의 안정성이 확보되는 것으로 이어진다. 그렇다고 해서 너무 막대한 비용을 요구하면 복구 기간 (t_1과 t_2) 동안 묶이는 돈이 많아지므로 불편 요소가 된다. 이러한 파라미터들을 잘 조정하는 것이 중요하겠다. 바로 다음 장에서 살펴보자.

프로토콜 파라미터들

kELP 프로토콜에서 언급되는 파라미터는 다음의 네 개이다:

  • t_1: 커미트먼트가 공개되어야 하는 시간의 상한
  • t_2: 주장을 하기 까지 기다려야 하는 시간의 하한
  • fee_1: Commit 트랜잭션에 청구되는 추가 수수료
  • fee_2: Reveal 트랜잭션에 청구되는 추가 수수료

이들의 최적값은 블록체인 프로토콜마다 달라진다. 합의알고리즘에 따라 완결에 소요되는 시간이 차이 날 수 있고, 블록체인 구조도 차이가 나며(UTXO냐 계좌 기반이냐), 탈중앙화 정도에도 차이가 있기 때문이다. 대신에 값을 설정하는 것에 필요한 고려 사항들은 나열해 볼 수 있다.

t_1

t_1의 의의는 등록된 주장이 공개될 것인지 비밀로 남을 것인지를 결정짓는 상한이라는 점에 있다. 프론트러닝 공격을 막기 위해 t_1은 트랜잭션이 완결되는 기간보다 짧아서는 안 된다. 예를 들어, 만약 Commit 트랜잭션이 아직 완결되지 않았는데 Reveal이 가능하면 주소 address_c가 노출될 수 있다. 이에 채굴자나 블록 생성자가 자신이 생성한 Commit 및 Reveal 트랜잭션으로 기존 트랜잭션들을 대체할 수 있으므로 주의가 필요한 것이다.

그렇다고 해서 t_1이 너무 큰 값이 되거나 무한하다면 이는 공격자들이 매우 많은 주장을 남발할 수 있게 하는 공격 요소가 될 수 있다. 이러한 주장들은 블록체인에 오래 남아 있어야 하고, 그만큼 노드들에게 부담을 주게 된다.

이런 점들을 고려해 t_1은 수 시간에서 수 일로 설정하는 것이 좋다고 저자들은 말하고 있다.

t_2

t_2의 의의는 적법한 사용자가 공격자의 주장에 충분히 대응할 시간을 주는 것이다. 따라서:

  • 그들 주소에 대한 주장을 검출할 수 있을 만큼
  • 활성화된 주장에 대한 Challenge 트랜잭션을 수행할 만큼

충분해야 한다. 이들 둘 다 충분한 시간을 필요로 하는 만큼 t_2는 길어질 수밖에 없다. 이에 저자들은 수개월에서 심지어 몇 년을 제안하고 있다.

fee_1

fee_1은 Commit 트랜잭션을 통한 공격과 남발을 막기 위해 요구된다.

Commit 트랜잭션을 통해서는 어떠한 정보도 누출되면 안 되기 때문에, fee_1을 잔액에 비례해서 할당하는 방법은 적절하지 못하다. 그러나 fee_1을 적절히 크게 설정해야지만 막대한 양의 Commit 남발을 막을 수 있기 때문에, 생태계 전반에 걸쳐 합리적인 fee_1 산정 전략이 필요하다.

한 가지 방법은 fee_1을 네트워크 전체 잔액의 평균에 비례하게 설정하는 것이다. 예를 들어, 전체 계좌들의 잔액을 합치면 $1,000라고 하자. 이때 fee_1을 비례하게 설정해 $100으로 할당할 수 있다.

이 방법을 통하면 대다수 계좌에 대한 Commit 트랜잭션을 보내는 것이 사실상 불가능해진다. 적법한 사용자라면 나중에 이 금액만큼을 회수할 것이므로, (스테이블하다면) 크게 문제가 되지 않을 것이다.

fee_2

fee_2는 Reveal 트랜잭션의 비용을 올리기 위한 수단으로 사용된다. fee_1과 유사하지만, fee_1은 은닉성을 위해 차등을 주지 못했다면 Reveal에서는 차등을 둘 수 있다. 사실 차등을 주는 것이 맞다. 공격자 입장에서는 같은 비용을 들여 더 많은 잔액을 얻고자 할 것이기 때문이다.

그래서 fee_2는 복구를 주장하는 잔액에 비례하게 할당해야 한다.

KELP 프로토콜의 아이디어 자체는 매우 간단하지만, 실제로 현재까지 제시된 계좌 복구 방법론 중 유일한 사후 처리가 가능하다는 점에서 강력하다. 또한 t_1과 t_2, 그리고 fee_1과 fee_2로 대변되는 파라미터들이 체인 종류에 따라 조정 가능하다는 점에서 유연하다.

당장은 이러한 프로토콜이 크게 필요치 않아 보이더라도 앞으로 디파이 생태계가 커지고 블록체인이 은행의 역할을 대신하게 되면서 재조명 받지 않을까 싶다. 원래 자산의 잘못된 전송이나 암호 유실 등의 사건 사고는 중앙화된 기관의 힘을 빌려 해결했으나, 탈중앙화 철학을 지키면서도 복구 가능한 방법을 제시했다는 점에서 훌륭하다.

D3LAB에서는 이러한 문제상황을 인지하고 해결책을 구현하고 있다[2][3]. 현재 기획이 완료된 상태고 본격적인 구현에 막 들어서고 있는데, 프로토타입이 나오고 나면 더 자세히 소개해보도록 하겠다.

이 글은 CURG 활동의 일환으로 작성되었습니다.

CURG(Crypto United Research Group)는 2018년 5월 대학(원), 기업, 스타트업 등 다양한 분야의 열정적인 블록체인-er들이 모인 연합 연구 그룹입니다. CURG는 2018년 5월 출범된 이후, ‘Trendy, Thoughtful, and Transdisciplinary’ 한 자세로 한 주도 빠짐없이 블록체인 연구를 지속해오고 있습니다.

--

--