저자: 파우스트, 괴짜 web3
소개: 최근 Vitalik과 일부 학자들은 Tornado Cash가 어떻게 안티-시 자금 솔루션을 구현할 수 있는지 언급하는 새로운 논문을 공동으로 발표했습니다. ), 하지만 토네이도 캐시에 대한 이해가 부족한 기사입니다. 캐시의 비즈니스 로직과 원리에 대한 상세한 해석은 사람들이 이해하는 것처럼 보이지만 아직 이해하지 못하는 느낌을 줍니다.
또한 Tornado로 대표되는 개인 정보 보호 프로젝트는 실제로 ZK-SNARK 알고리즘의 영지식 특성을 사용하는 반면 ZK 배너 아래의 대부분의 롤업은 ZK-SNARK의 단순성만 사용한다는 점을 언급할 가치가 있습니다. 많은 사람들이 Validity Proof와 ZK의 차이점을 혼동하는 경향이 있으며, Tornado는 ZK 애플리케이션을 이해하는 데 탁월한 사례입니다.
이 글의 저자는 우연히 2022년 Web3Caff Research에 토네이도의 원리에 관한 글을 작성하게 되었습니다. 오늘은 토네이도 캐시를 누구나 체계적으로 이해할 수 있도록 그 문단 중 일부를 발췌, 확대하여 문서로 정리했습니다.
원본 링크:
https://research.web3caff.com/zh/archives/2663?ref=157
토네이도의 원리
토네이도 캐시(Tornado Cash)는 영지식증명을 활용한 코인믹서 프로토콜로, 2019년 구 버전이 출시됐고, 2021년 말 새 버전이 베타 버전을 출시했다. Tornado의 이전 버전은 기본적으로 분산화되어 있습니다. 체인의 계약은 오픈 소스이며 다중 서명 제어가 없습니다. 프런트 엔드 코드는 오픈 소스이며 IPFS 네트워크에 백업됩니다. 토네이도는 구 버전의 전체적인 구조가 더 간단하고 이해하기 쉽기 때문에, 이번 글에서는 구 버전을 설명하겠습니다.
Tornado의 주요 아이디어는 대량의 입출금을 혼합하는 것인데, 예금자가 Tornado에 Token을 입금한 후 ZK Proof를 제시하여 입금을 증명한 후 A를 사용합니다. 돈을 인출할 새로운 주소로 인해 입출금 주소가 차단됩니다.
좀 더 구체적으로 말하면 토네이도는 많은 사람들의 동전이 섞여 있는 유리 상자와 같습니다. 누가 동전을 넣었는지는 알 수 있지만 이 동전들은 동질성이 매우 높아 낯선 사람이 유리상자에서 동전을 가져가면 원래 가져간 동전을 누가 넣었는지 알기가 어렵습니다.
좀 더 구체적으로 말하면 토네이도는 많은 사람들의 동전이 섞여 있는 유리 상자와 같습니다. 누가 동전을 넣었는지는 알 수 있지만 이 동전들은 동질성이 매우 높아 낯선 사람이 유리상자에서 동전을 가져가면 원래 가져간 동전을 누가 넣었는지 알기가 어렵습니다.
이 시나리오는 일반적인 것으로 보입니다. Uniswap 풀에서 몇 개의 ETH를 교환할 때 Uniswap에 유동성을 제공한 사람이 너무 많기 때문에 누가 제거된 ETH를 제공했는지 알 방법이 없습니다. 그러나 차이점은 Uniswap을 사용하여 토큰을 전송할 때마다 다른 토큰을 등가 비용으로 사용해야 하며 자금을 다른 사람에게 "비공개"로 전송할 수 없다는 것입니다. ...
입출금 행위가 동질적으로 보이도록 하기 위해 토네이도 풀의 예금 주소로 입금된 자금과 출금 주소로 출금된 자금이 매번 일관되게 유지됩니다. 예를 들어 특정 풀에서는 예금자 100명, 출금 100명이 공개적으로 표시되지만 , 서로 아무런 연관이 없는 것으로 보이며, 각 개인이 입출금하는 금액은 동일합니다. 이때 입출금 금액을 기준으로 대중을 혼란스럽게 하고 상관관계를 판단할 수 없도록 함으로써 자금 이체의 흔적을 차단할 수 있으며, 이는 당연히 돈 버는 행위에 자연스러운 편의를 제공합니다.
그러나 중요한 질문이 있습니다. 인출자가 돈을 인출할 때 돈을 예치했다는 것을 어떻게 증명할 수 있습니까? 믹서에서 출금을 시작하는 주소는 입금 주소와 관련이 없는데 출금 자격을 어떻게 확인할 수 있습니까? 가장 직접적인 방법은 출금자가 자신이 어떤 입금기록을 했는지 직접 공개하는 방법인 것 같은데, 이는 직접적으로 본인의 신원을 드러낸다. 이것이 영지식 증명이 유용한 곳입니다.
인출자는 Tornado 계약에 예금 기록이 있고 예금이 인출되지 않았음을 증명하기 위해 ZK 증명을 발행하여 인출을 성공적으로 시작할 수 있습니다. 영지식 증명 자체가 프라이버시 보호를 실현하는데, 외부 세계에서는 출금자가 실제로 자금 풀에 돈을 입금했다는 사실만 알 뿐, 그가 어느 예금자에 해당하는지 알 수 없습니다.
"내가 토네이도 펀드 풀에 돈을 예치했다"는 것을 증명하려면 "나의 예금 기록은 토네이도 계약서에서 확인할 수 있습니다"로 변환할 수 있습니다. Cn을 사용하여 예금 기록을 표현하는 경우 문제는 다음과 같이 요약될 수 있습니다.
Tornado의 입금 기록 세트는 {C1, C2,...C100...}인 것으로 알려져 있는데, 출금자 Bob은 자신의 손에 있는 키를 사용하여 입금 기록에서 특정 Cn을 생성했음을 증명하지만 ZK는 그렇지 않습니다. Cn이 무엇인지 밝혀주세요.
Merkle Proof의 특별한 속성이 여기에 사용됩니다. 토네이도의 모든 예금 기록은 체인의 최하위 리프 노드로 구성된 MerkleTree에 저장되고 총 리프 수는 약 2의 20승 > 100만이므로 대부분은 공백 상태입니다(초기값에 따라) 값). 새로운 예금이 발생할 때마다 계약은 해당 특성 값인 Commitment를 리프에 기록한 다음 Merkle Tree의 루트를 업데이트합니다.
예를 들어 Bob의 입금 작업이 토네이도 역사상 10,000번째인 경우 이 입금과 관련된 특성값 Cn이 머클 트리의 10,000번째 리프 노드에 기록됩니다. 즉, C10000 = Cn입니다. 그런 다음 계약은 자동으로 새 루트를 계산하고 업데이트합니다. (ps: 계산량을 절약하기 위해 Tornado 컨트랙트는 변경된 노드의 이전 배치 데이터(아래 그림의 Fs1, Fs2, Fs0 등)를 캐시합니다.)
MerkleProof 자체는 매우 간단하고 가볍습니다. 검색/소스 추적 프로세스에서 트리 데이터 구조의 단순성을 활용합니다. MerkleTree에 특정 거래 TD가 존재한다는 것을 외부적으로 증명하려면 Root에 해당하는 MerkleProof(아래 그림의 오른쪽 부분)만 주면 되는데, 꽤 간단합니다. 머클 트리가 매우 크고 맨 아래 잎의 2의 20승이 즉, 100만 개의 입금 기록을 포함한다면 머클 증명에는 21개의 노드 값만 포함하면 되는데, 이는 매우 짧습니다.
특정 트랜잭션 H3가 실제로 머클 트리에 포함되어 있음을 증명하려면 머클 트리의 H3 및 기타 부분 데이터를 사용하여 Root를 생성할 수 있고, Root 생성에 필요한 데이터 부분(포함)을 증명해 보세요. Td)는 머클 증명을 구성합니다.
Bob이 돈을 인출할 때, Bob은 자신이 소유한 인증서가 Merkle Tree에 기록된 특정 예금 해시 Cn과 일치한다는 것을 증명해야 합니다. 즉, 그는 두 가지를 증명하고 싶어합니다.
·Cn은 체인의 Tornado 계약에 있는 Merkle Tree에 존재하며, 구체적으로 Cn을 포함하는 Merkle Proof를 구성할 수 있습니다.
·Cn은 Bob의 손에 있는 예금 증서와 관련이 있습니다.
Tornado 비즈니스 로직에 대한 자세한 설명
Tornado 비즈니스 로직에 대한 자세한 설명
Tornado 사용자 인터페이스의 프런트엔드 코드에는 사전에 많은 기능이 구현되어 있는데 예금자가 TornadoCash 웹페이지를 열고 입금 버튼을 클릭하면 프런트엔드 코드에 첨부된 프로그램이 로컬에서 두 개의 난수 K와 r을 생성합니다. , 그리고 Cn=Hash를 계산합니다. (K, r)의 값은 Tornado 계약에 전달되고 Cn(아래 그림의 커밋)은 후자에 의해 기록된 Merkle Tree에 삽입됩니다. 직설적으로 말하면 K와 r은 개인 키와 동일합니다. 이는 중요하며 사용자에게 이를 올바르게 저장하라는 메시지가 표시됩니다. K와 r은 나중에 돈을 인출할 때 계속 사용됩니다.
위의 작업이 모두 오프체인에서 발생한다는 점은 주목할 가치가 있습니다. 즉, Tornado 계약도 외부 관찰자도 K와 r을 알지 못합니다. K와 r이 유출된다면 지갑 개인키를 도난당하는 것과 유사합니다.
Tornado 계약은 사용자의 보증금을 받고 사용자가 제출한 Cn=Hash(K, r)을 받은 후 Cn을 Merkle 트리의 맨 아래 레이어에 새 리프 노드로 삽입하고 Root 값을 업데이트합니다. 따라서 Cn은 사용자의 입금 행위와 일대일로 관련되어 있으며, 외부에서는 각 Cn이 어떤 사용자에 해당하는지, 누가 믹서에 토큰을 입금했는지, 각 입금자에 해당하는 입금 기록을 알 수 있습니다.
출금 단계에서 출금자는 프런트 엔드 웹 페이지에 인증서/개인 키(입금 시 생성된 임의의 숫자 K 및 r)를 입력합니다. TornadoCash 프런트 엔드 코드의 프로그램은 K와 r, Cn=Hash( K, r), Cn 해당 Merkle Proof는 ZK Proof를 생성하기 위한 입력 매개변수로 사용되며, 이는 Cn이 Merkle Tree에 존재하는 특정 예금 기록이고 K와 r이 Cn에 해당하는 인증서임을 증명합니다.
이 단계는 머클 트리에 기록된 특정 예금 기록에 해당하는 키를 알고 있음을 증명하는 것과 같습니다. ZK Proof가 Tornado 계약에 제출되면 위의 4가지 매개변수가 숨겨져 외부 세계(Tornado 계약 포함)에 알 수 없으므로 개인정보 보호가 보장됩니다.
ZKProof 생성과 관련된 다른 매개변수에는 돈을 인출할 때 Tornado 계약의 Merkle Tree 루트, 맞춤형 지불 주소 A, 재생 공격을 방지하기 위한 식별자 nf(나중에 논의됨)가 포함됩니다. 이 세 가지 매개 변수는 체인에 공개적으로 게시되며 외부 세계에 알려질 수 있지만 개인 정보 보호에는 영향을 미치지 않습니다.
여기에는 세부 사항이 있습니다. 즉, 입금 작업이 Cn을 생성할 때 단일 난수 대신 두 개의 난수 K와 r을 사용하여 Cn을 생성합니다. 이는 하나의 난수로는 충분히 안전하지 않고 일정한 충돌 확률이 있기 때문입니다.예를 들어 하나의 난수를 사용하면 두 명의 다른 예금자가 우연히 동일한 난수를 사용하여 생성된 Cn이 충돌할 수 있습니다.
여기에는 세부 사항이 있습니다. 즉, 입금 작업이 Cn을 생성할 때 단일 난수 대신 두 개의 난수 K와 r을 사용하여 Cn을 생성합니다. 이는 하나의 난수로는 충분히 안전하지 않고 일정한 충돌 확률이 있기 때문입니다.예를 들어 하나의 난수를 사용하면 두 명의 다른 예금자가 우연히 동일한 난수를 사용하여 생성된 Cn이 충돌할 수 있습니다.
위 그림의 A는 출금자가 입력하는 출금수령 주소를 나타냅니다. nf는 재생 공격을 방지하기 위한 식별자로, 그 값은 nf = Hash(K)이고, K는 Cn을 입금하는 단계에서 사용되는 두 개의 난수(K, r) 중 하나이다. 이런 식으로 nf는 Cn과 연관되어 있는데, 즉 각각의 Cn은 대응하는 nf를 가지며, 둘은 하나씩 연관되어 있다.
재생 공격을 방지하는 이유는 무엇입니까? 코인믹서의 설계 특성상 자금 출금 시 사용자가 출금한 코인에 해당하는 머클 트리의 리프 Cn이 무엇인지 알 수 없으므로 출금자가 어느 예금자와 관련이 있는지, 몇 개인지 알 수 없습니다. 출금자가 입금한 금액 두 번째 지불 출금자는 이 기능을 사용하여 자주 자금을 인출하고, 재생 공격을 시작하고, 자금 풀이 고갈될 때까지 혼합 풀에서 토큰을 여러 번 가져올 수 있습니다.
여기서 nf 식별자의 역할은 각 이더리움 주소가 가지고 있는 트랜잭션 카운터 nonce와 유사하며 특정 트랜잭션이 재생되지 않도록 설정됩니다. 출금이 발생하면 출금자는 nf를 제출하여 해당 nf가 사용(기록)되었는지 확인해야 하며, 그렇다면 출금이 무효입니다. 그렇지 않은 경우 nf가 사용되지 않았음을 의미하며 출금이 유효하며 해당 nf가 기록됩니다. 다음에 누군가가 이 nf를 제출하면 해당 철회 조치가 유효하지 않은 것으로 직접 결정됩니다.
계약서에 기록되지 않은 nf를 누군가 임의로 생성해도 괜찮나요? 물론 그렇지 않습니다. 왜냐하면 출금자가 ZK 증명을 생성할 때 nf = Hash(K)인지 확인해야 하고 난수 K가 예금 기록 Cn과 연관되어 있기 때문입니다. 즉, nf는 특정 기록된 예금과 연관되어 있습니다. Cn. 마음대로 nf를 구성했는데 이 nf가 입금 기록의 모든 입금액과 일치하지 않는 경우 유효한 ZK 증명이 원활하게 생성되지 않고 후속 작업이 원활하게 완료되지 않으며 출금 작업이 성공하지 못합니다.
어떤 사람들은 다음과 같이 질문할 수도 있습니다. NF 없이도 가능합니까? 출금자는 특정 Cn과 관련되어 있음을 증명하기 위해 돈을 출금할 때 ZK 증명을 제출해야 하기 때문에, 출금이 발생할 때마다 해당 ZK 증명이 체인에 제출되었는지 확인하는 것으로 충분하지 않을까요?
그러나 실제로 이를 수행하는 데 드는 비용은 매우 높습니다. 왜냐하면 Tornado 현금 계약은 과거에 제출된 ZK 증명을 영구적으로 저장하지 않기 때문입니다. 이는 저장 공간을 심각하게 낭비하게 되기 때문입니다. 체인에 제출된 각각의 새로운 ZKProof가 기존 Proof와 일치하는지 비교하는 것보다 작은 영역을 차지하는 식별자 nf를 설정하여 영구적으로 저장하는 것이 더 비용 효율적입니다.
출금 기능의 코드 예시에 따르면 필수 매개변수와 비즈니스 로직은 다음과 같습니다.
사용자는 ZKProof, nf(NullifierHash) = Hash(K)를 제출하고 출금을 받을 주소 수신자를 맞춤화합니다. ZKProof는 Cn, K, r 값을 숨기므로 외부 세계에서 획득 및 인출이 불가능합니다. 사용자의 신원을 확인합니다. 리전트는 종종 깨끗한 새 주소를 작성하고 개인 정보를 공개하지 않습니다.
사용자는 ZKProof, nf(NullifierHash) = Hash(K)를 제출하고 출금을 받을 주소 수신자를 맞춤화합니다. ZKProof는 Cn, K, r 값을 숨기므로 외부 세계에서 획득 및 인출이 불가능합니다. 사용자의 신원을 확인합니다. 리전트는 종종 깨끗한 새 주소를 작성하고 개인 정보를 공개하지 않습니다.
그러나 여기에는 작은 문제가 있습니다. 즉, 사용자가 돈을 인출할 때 추적성을 피하기 위해 새로 적용한 주소를 사용하여 인출 거래를 시작하는 경우가 많습니다. 이때 새 주소에는 가스를 지불할 ETH가 없습니다. 요금. 따라서 출금 주소가 출금을 개시할 때 가스비를 지불할 중계인을 명시적으로 선언해야 하며, 그러면 믹서 계약은 사용자의 출금 금액 중 일부를 직접 차감하여 중계인에게 대가로 지급합니다.
정리하자면, TornadoCash는 출금자와 예금자 사이의 관계를 은폐할 수 있습니다. 사용자가 많을 때는 도심과 같으며, 일단 범인이 군중 속에 섞여들면 경찰이 추적하기 어렵습니다. . 출금 과정에서 ZK-SNARK가 필요하며 숨겨진 증인 부분에는 출금자의 주요 정보가 포함되어 있으며 이는 전체 코인 믹서의 가장 중요한 포인트입니다. 현재로서는 Tornado는 ZK와 관련된 가장 독창적인 애플리케이션 레이어 프로젝트 중 하나일 수 있습니다.
모든 댓글