소개
zkevms의 상용화로 인해 이더리움 가상 머신(EVM) 호환성을 유지하면서 프라이빗 스마트 컨트랙트 인프라를 제공할 수 있는 흥미로운 기회가 생겨났습니다. 개발자는 솔리디티 작성하고 특정 버전의 솔리디티 컴파일러나 일부 후처리 도구를 사용하여 컴파일할 수 있습니다. 이를 통해 프라이빗 스마트 컨트랙트를 만들 수 있습니다.
프라이빗 글로벌 상태와 프라이버시 사이에는 중요한 상충 관계가 있는데, 이는 증명하기 위해서는 무엇을 증명하는지 알아야 한다는 개념에서 비롯됩니다. 따라서 알지 못하는 글로벌 퍼블릭 상태를 가진 프라이빗 스마트 컨트랙트를 만들 수 없습니다. 따라서 글로벌 프라이빗 상태를 가진 프라이빗 스마트 컨트랙트를 만들 수 없습니다. 예를 들어, 유니스왑(Uniswap) 불가능합니다. 증명자가 스왑이 올바르게 수행되었음을 증명하기 위해 두 풀의 잔액을 알아야 하기 때문입니다. 이에 대한 자세한 내용은 bowaggoner의 ZKPs를 사용하여 프라이빗 유니스왑(Uniswap) 구축할 수 없는 이유 - #24를 참조 하세요.
따라서 우리가 알고 좋아하는 것들 중 일부는 IO가 있기 전까지는 비공개 방식으로 구현하는 것이 불가능합니다. 바로 이 때문에 IO가 매우 중요합니다. IO를 통해 완전히 비공개적인 이더리움을 만들 수 있습니다. IO는 동일한 신뢰 가정을 기반으로 합니다.
어쨌든 이 글은 pstore와 pload에 두 개의 명령어를 추가하는 방법과 이를 zkevm으로 컴파일하여 개인 사용자 상태는 있지만 개인 글로벌 상태는 없는 개인 스마트 계약을 갖는 방법에 대한 것입니다.
어떻게
비공개적인 특정 계약 호출이 있습니다. 저희는 zkevm 코드를 활용하여 해당 호출이 올바르게 실행되었음을 증명하지만, 계약이 실제로 수행한 작업에 대한 정보는 공개하지 않습니다. 특정 요구 사항, 예를 들어 특정 수의 토큰이 다른 계약에서 사용 승인을 받았는지 여부(who's tokens)를 충족하는 것 외에는, sload 및 sstore와 유사한 두 가지 새로운 옵티미즘(OP) 코드인 pstore와 pload를 구현합니다. 다만 값은 비공개입니다.
도구 상자
zkevm을 도구 체인으로 사용합니다. zkevm 자체는 변경하지 않습니다. 이 부분은 블랙박스로 간주하겠습니다. 대신 reth를 변경하겠습니다. reth에 두 개의 새로운 트리를 추가하도록 하겠습니다. 개인 저장소 트리(PST)와 개인 무효화 트리(PNT)입니다.
PST와 PNT의 각 리프는 업데이트될 때마다 게시됩니다. 따라서 누구나 어떤 리프의 멤버십을 증명할 수 있습니다. 하지만 이러한 리프에 포함된 값은 리프를 만든 사용자만 알 수 있습니다.
로드하다
pload는 우리가 추가하는 이더리움 가상 머신(EVM) 명령어입니다. sload와 유사합니다. zkevm에서 sload를 실행하면 zkzkevm은 특정 값이 트리의 특정 위치에 있다는 것을 머클 증명으로 증명합니다.
마찬가지로 pload의 경우 트리의 해당 리프에 대한 멤버십 증명을 하지만 해당 리프가 무효화되지 않았다는 것도 증명합니다.
값 x를 로드하려고 한다고 가정해 보겠습니다. 기본적으로 우리는 두 개의 머클 증명을 수행합니다.
- PST에서 x를 증명하세요
- x.nullifier가 PNT에 없다는 것을 증명하세요
해당 리프의 비밀 값을 아는 사용자만이 무효화 함수를 계산할 수 있으며, 그러한 사용자만이 무효화되지 않았음을 증명할 수 있습니다.
참고: sload는 순서가 있는 메르켈 트리를 사용하므로 암묵적으로 불포함 증명을 가집니다. pload와 pstore에는 순서가 있는 메르켈 트리를 사용할 수 없으므로, 주어진 리프가 생성되지 않았음을 보장하는 인코딩이 필요합니다. 이러한 인코딩은 해시 (계약, 슬롯, 값, 널리파이어)와 같은 형태가 될 수 있습니다.
참고: 아무것도 없는 주소를 sload하면 0x0이 반환되는데, 이 부분도 고려해야 할 것 같습니다. zkzkevm에서 동일한 devex가 존재하도록 이 문제를 처리하는 방법을 생각해 봐야 할 것 같습니다. 하지만 저장 슬롯이 채워지지 않았다는 것을 증명하기는 어렵습니다.
p스토어
pstore는 sstore와 동일한 기능을 합니다. 하지만 작동 방식이 비트(Bit) 다릅니다.
zkevm에서는 sstore가 수행될 때마다 사실상 두 번의 머클 증명을 수행합니다. 첫 번째는 리프 노드의 현재 값이 x임을 증명하고, 두 번째 머클 증명은 x 값을 y로 대체할 때 머클 루트를 계산합니다. 따라서 첫 번째 증명은 트리의 모든 리프 노드에 대한 요약 증명을 얻는 것으로, 두 번째 증명은 단일 리프 노드(x)만 y로 대체하는 것으로 생각할 수 있습니다.
그래서 저장하다
- 값 x가 트리에 있음을 증명하세요
- y로 대체합니다
pstore는 동일한 작업을 수행할 수 있지만 비트(Bit) 다릅니다.
- x.nullifier를 가져와서 nullifier 트리에 추가하여 x를 제거합니다.
- PST에 x를 추가하여 y로 바꿉니다.
솔리디티
솔리디티 이더리움 가상 머신(EVM) 명령어로 컴파일됩니다.
다음과 같은 스마트 계약이 있다고 가정해 보겠습니다.
def transfer(sender, reciver, amount) private:bal[sender]= bal[sender] - amountbal[reciver] = bal[reciver] + amount# this is not adding to the users balance directly. Instead it is kind of input out put thing where the user needs to get the received funds to add to their total balance. This nuance is encapsulated in a receiver address abstraction for now. But needs more work to figure out what is needed on zkzkevm side.return(1)(일부 포스트 프로세서의) 솔리디티 컴파일러는 이를 감지하고 바이트코드의 모든 sloads/sstore를 ploads/pstores로 대체합니다. private 수정자나 태그가 있는 함수에 대해서만 이 작업을 수행합니다.
일부 개인 레그와 일부 공개 레그가 있는 콜 체인
이를 Aztec Connect의 프로그래밍 가능한 버전이라고 생각해 보세요. 예를 들어, 개인 지갑이 있어서 해당 지갑에서 유니스왑(Uniswap) 호출하도록 할 수 있습니다. 이렇게 할 수는 있지만, message.sender, tx.origin, 논스 , gas_price, gas_limit 및 기타 메타 데이터 유출을 신중하게 처리해야 합니다. 이를 위한 몇 가지 방법이 있습니다.
- 각 호출에 대한 프록시 계약을 만든 다음 다른 tx 또는 현재 tx 호출 스택의 끝에서 재조정합니다.
- 글로벌 프록시 계약을 사용하세요
참고: reth 변경 시 tx.origin을 정제해야 할 수도 있습니다. 하지만 아마도 번들러일 뿐이니 크게 문제될 건 없을 것 같습니다.
트레이드오프
아즈텍을 연결하는 것만으로도 이 모든 것이 비트(Bit) 복잡해 보일 수 있습니다. 하지만 이 기술의 핵심은 현재 우리가 보유한 대부분의 인프라를 재활용하여 훨씬 더 강력한 애플리케이션을 구현할 수 있다는 것입니다.
카르텔 계약
프라이빗 글로벌 상태와 유니스왑(Uniswap) 등을 구현하는 것이 불가능하다는 점에 대해 비트(Bit) 이야기했습니다. 하지만 저와 제 친구들을 위한 스마트 컨트랙트를 만들고 싶다고 가정해 보겠습니다. 소스 코드는 공개적으로 비공개로 유지하면서 저와 제 친구들이 실행할 수 있도록 하고 싶습니다. 스마트 컨트랙트의 데이터 가용성 보장을 완화하여 스마트 컨트랙트 코드를 공개할 필요가 없도록 하면 됩니다.
카르텔 내부에서는 데이터 가용성 보장에 대해 미묘한 차이가 있습니다. 모든 데이터 업데이트가 암호화되어 카르텔 회원만 볼 수 있도록 하는 일종의 강제 로깅 시스템을 구현할 수도 있을 것 같습니다.
결론
이 아이디어는 두 가지 면에서 즉시 유용할 것으로 보입니다.
- 사용자가 자신의 데이터를 이 서버에만 제공하고 다른 모든 사람에게는 제공하지 않는다는 모든 증거를 괴물 서버가 만드는 개인 롤업 만들기
- 사용자가 일부 증거를 만들어 저장 공간에 대한 접근 권한을 거대한 서버에서 숨기는 개인 롤업입니다.
유용하고 구현하기 쉬운 것 같습니다. zk를 필수 요소로 여기기 때문에 zk에 대한 지식이 필요 없습니다.
할 일
우리는 더 많이 생각해야 합니다
- EOA를 기본적으로 비공개로 설정해야 할까요? "nullifier"에 서명하게 하고 그 임의의 문자열을 nullfier로 만드는 것과 같은 몇 가지 nullifier 트릭을 사용하면 가능할 것 같습니다. 또는 nullifier_0 = 해시 (sign("nullfiier") , 0 ) nullifier_1 = 해시(sign("nullifier",1)) 과 같은 방식입니다. 하지만 이렇게 하려면 모든 ERC20 컨트랙트가 ERC20에서 pstore와 pload를 사용하도록 컴파일해야 합니다. 이렇게 하면 다른 문제가 발생할 수 있습니다. 하지만 수동 EOA 비공개 설정에는 상태 변경이 포함되지 않는 것 같습니다. 대부분 사람들이 ERC20보다는 이더리움(ETH) 에 더 관심이 있기 때문입니다.
- 모바일에서 몇 가지 느슨한 것들에 대한 zkevm 증명을 만드는 것이 가능할까요? 몇 번의 pload가 필요합니다.
- pstoreing하는 값이 동적으로 생성되는 경우 경쟁 조건으로 인해 전체 리프를 만드는 것보다 괴물 서버가 리프를 저장하는 데 사용할 수 있는 무효화기를 갖는 것이 더 좋습니다.
- 모든 영수증을 연결하지 않고도 개인적으로 자금을 받을 수 있도록 주소를 제공하는 방법
- 로깅이나 다른 구문을 사용하여 자금을 받았는지 확인할 수 있는 방법은 무엇인가요? 암호화된 "플래그"를 포함한 로그를 반환하는 것만큼 간단할 것 같습니다.



