Trust-minimized wallets with purified web3 - Etan Kissling
EthereumZuri.ch 2025 · 31 Jan 2025 · 28:58
Etan Kissling presents an approach to trust-minimized wallets built on purified web3 at EthereumZuri.ch 2025. The talk looks at how a wallet can cut the trust it places in the infrastructure it relies on, a recurring concern for Ethereum users who depend on outside providers for the chain data their wallets display.
Speakers
Topics
From EthereumZuri.ch 2025, hosted by EthereumZuri.ch.
Transcript
[Music] can you hear me all right slides are also here so hello and welcome to my talk about trust minimized wallets like the session before this is all about wallets doesn't matter what flavor can be a mobile app or a browser extension and it's also about wallet security so some of you may use this Hardware wallets like the little Ledger devices and they are great tools to protect your private key you can securely sign transactions with them but what they do not help you is to secure
the wallet itself like what it displays the ethereum balance the tokens and your account history here in the bottom so to understand how this gets secured we have to look at how the wallet obtains data like how does it obtain um the balance for example and the answer to that is ethereum as a decentralized network every single ethereum node has a full copy of all the account balances all the transactions whatsoever and if you catch one with a public RPC like that's exposed you can ask it for your balance and it will comply and send you your
balance um the issue here is the security though like this is all based on trust me bro security so if if you connect a malicious Noe it can tell you a wrong balance uh which can be a problem like for refund scams and whatsoever so how to fix it is that some users they decide to run their own noes like they set up a Raspberry Pi at home and then configure their wallet to ask the Raspberry Pi and because that one is running a full node it can run the full validation and ensure that it only provides correct data it's a bit of an issue though because you have now this
extra box in your home if you want it on your phone then you are going to struggle because we are still having the requirement for like the four core CPU which is possible on phones now but you also need 16 gigs of RAM and two terabytes of dis which is still a bit too much these days so how to make it more convenient is um the answer is go to the cloud there are web 3 API providers that um have this capability as well you can just connect to a server ask them for your data and they will send it to you and the security here is a bit better because those companies have a
reputation that they can lose if they are known to provide wrong data but it's still a trusted relationship I'm putting here this little glow on top of them and if you look at this it also means that all of this decentralized stuff on the right it kind of becomes Irrelevant for how the wallet operates so this is also shown by the security features that are unlocked by the central provider likely down times like if they are down your wallet doesn't work if they get hacked you exposed to their security they can also geoblock you like if if you're a resident of a country that they don't like you don't
have access to your wallet and there's also this privacy problem that a lot of these providers start to have privacy policies where even if you segregate your funds across multiple Ledger devices that they still see um that the same IP is asking about multiple wallets and they they likely belong to the same in person if that keeps happening but on the other end there are also advantages like it works on mobile this is what we try to solve and it's also very cheap to run like uh any wallet that we use is essentially free to use right so when we have this tradeoff downsides upsides usually the
convenience wins and over time this also means that there is some consolidation happening and these days most wallets just rely on infura or Alchemy to provide the correct data so that's today's reality and now the question is how do we get better than that and the answer to that starts with EIP 1186 eate proof and it works by adding a correctness proof to the response so this means that now the Sur provides the proof that the data itself is correct and when we verify that it makes this trust relationship disaar we
only rely on the server now for data availability because we can verify that it's not lying anymore and because the server gives a proof it also means that we can now ask any server for the data and this is great for decentralization because we have a convenient system that works and that's also secure um to understand this proof on a technical level we have to understand how ethereum stores its data all the account balances are stored in a tree structure um and your address like the wallet address can be used to identify where in this tree your um balance is
located and there is something called the state root which is like the the root hash of this tree a commitment to all of this data and we want to be able to compute it to to verify this proof and for that we have to understand how to compute all those intermediate nodes and it's a Merkel Patricia try the way how it works is for every inner node here it's a hash over all the children like here we have a binary tree um the reality is a bit more complex it's like uh multiple siblings that you need but as long as you have all of the children you can compute the next layer so in
order to obtain the state root we need all the siblings like these three elements and then we don't need to send any of the rest and we can compute the state Ro State Roo is also part of the block so if we compare it and it's the correct one then we know that the data has to be valid so problem shift to how do we know the correct state route right that we are expecting um and that's from the beacon chain like it's called the alter light client protocol and every single block is signed since proof of stake and there is a subset of validators called the syn committee it's
only 512 validators so it's uh very compact to track all those public keys and we with that we can check the signature and then know that the stat Ro is correct right this is a BLS aggregate signature if a super majority of the 512 Z committee members signed the message then we trust that it's right and this chicken and egg problem where how does the wallet know the public Keys is solved by just also having the next public key set as part of the response so you only need like an initial one that's hardcoded and then as
long as you get like one message per day you can follow all the s committees each of them retains its Duty for like 27 hours so one message per day is enough to follow the chain and obtain all the correct State TRS all of this is a bit complex to put in every wallet there are many wallets so it's nice that and there are also libraries that abstract it so the the wallet UI it can use like its same EET balance to this library and that one then does this SL client stuff and the E proof um to add the security so it's a universal API for the wallet instead of
using infura or Alchemy um ask your local purifier library and that one can then use any Upstream RPC in order to obtain the data and it's also secure like it's all verified there's also a decentralized network called portal Network which aims to be a um decentralized archive node so you don't even need a central server you can connect via a decentralized peer-to-peer Network and obtain all the data as well that solves it for the balance like we have a secure balance now but our wallet also has our um erc20 tokens and also the history so let's look at the
tokens next token is a smart contract and the smart contract uh like erc20 all of the tokens they Implement a shared interface and there is a function where you can query the balance of a wallet and in order to obtain the balance we have to call it there's a function called e call that we can send to the purifier and it will do its MTH magic so let's look at the magic because this is code from the smart contract we have to execute it in our local evm so the purifier comes with its own little execution engine it's like a little CPU architecture where you can run the smart
contract code and then we can download the code and put it in there and whenever as part of this execution we need access to some data from the state we can also do like this e get storage at to obtain the data and because the state tree that we have seen before doesn't only contain all the balances um but also all the code and all the storage slots we can use the same ethet proof infrastructure here and validate it with the same stage Ro as before that way we get a secure way to obtain token balances um this works for all nfts as well same same process one issue is that
it's a little bit inefficient because uh we we cannot know in advance what data we will need so there are a lot of round trips involved um like there are Concepts called access lists but they are best effort and don't always work very well but at least we get the security and once again for a wallet just add this web 3 purifier library and use it the same as any Upstream RPC today that only leaves the history and once again erc20 standard uh defines an event that's emitted on every token transfer um you can have like in
solidity up to three indexed values when you emit an event and every time that an event is emitted it generates something called a log and there is always an entry for the address of the contract that generates it then you can have up to four topics and the cool thing is that there is also an API called ethet logs where you can look up all the logs that affect your wallet um by just asking like because in the events like your address is in here right so you can just ask for your wallet in any of the topics and you will get all the logs that affect you and you can display them so problem here is uh we have these logs
how do we verify them right and the way how this works is that when we execute a transaction there is something called a receipt that captures all the output of the execution of the transaction and the logs are just a part of it and then we can do the same thing as with the state tree and just validate it using the alter light clent against the receipts root in the block header it's very similar to the state root but this one uh gets reset after every block so it doesn't uh carry on like the state that's persistent so that way we can validate the correctness of a receipt but there is still a problem when we do EET logs
we can validate every single response that the server gives us except the missing ones right if they just don't tell us about some logs um we we have no way to know that so how do we fix that um comes down to this field that's called The Log Bloom so how does the logs plume work is that um it's a bit Vector 2,48 bits and for every single item that is indexed like the address the four topics we set three bits based on some hash function
we do that for every indexed uh log value and we get like three bits for everyone and then we just Union them and this is our loog Blum how is this useful um let's look at a query let's say we look for our wallet address we can do the same transformation and find out what three bits our address um uh matches to and then if if all of these bits are also set in the loog blo then we know that there might be a match in the data and here indeed that's the case like our wallet is actually here the recipient of this particular log so
we see are the bits match so there has to be something in that block that might affect us let's ask about the different wallet that has different bits like it has a one here which is not um present in the locks Bloom so we know that for sure as part of this lock Bloom there is no single um item that went into it that set this particular bit so we can skip this data but um there can also be false positives like here we have a third wallet that we query which sets these three bits but we can see up here for these four values this was never put into this bit map so we can get some
false positive and then when we download the matching receipt and check it then only then we find out that this was not actually about our wallet so there is some inefficiency there and this loog Bloom is also part of the block header so we can also use the AL a light client to validate um that it's correct so how it would work is that you use the alter light client to download all the block headers you can do so both ways like first swing forward and then go by parent hash and then for every single block you can check is there something in this block that may affect our wallet and if
there is then download all the receipts and then filter them based on the ones that you care about there is an issue with this system that main it just grew very large right now we have about 1,000 of these indexed items that get put into a lock Blum on every single block and if each of them sets three bits that's like 3,000 bits in a data structure that's only 248 bits wide so there are a ton of false positives and this mechanism that was useful in the beginning of ethereum is no longer really useful let's look at the solution here
EIP 7745 live that aims to improve this filtering capability the way how this works by the way this is still ongoing work um you can comment on it leave feedback still this is not yet set in stone the way how it works is that all the logs that are emitted are assigned a global index for each of the topics and for the address and that just goes up with every single log that gets added 1 2 3 4 then 5 7 8 9 and so on so every single thing gets put into an ordered um indexed way and we don't actually care about the stuff that's not indexed here right so get rid
of the value for now and then one of the problems in the past with the logl is 2,000 bits is not enough so let's just make it bigger this is like 4,000 rows time 2 to the 32 lots of bits so no more false positives and now for every single log value like contract address this transfer the from to there is a transformation to compute the row so each of them gets assigned to row this is uh the the same Row for a really long time regardless of the instance so if you have a lot of locks that cover your wallet they will all end
up in the same row and then there is also a column transform that uh allows us to find a coordinate in that map that corresponds to this particular log like the index also goes in here so every single log value leaves one mark in this Matrix and this filter map because it's so big is also shared across blocks it's no more the case that every single block contains its own full filter method would be too too much storage so how do we query this filter map is uh when we have a log value as a query we compute the row from it that can be done on the client side and then
we know what row we need to download it's only a single one and now there are these two marks in here how do we know which of them correspond to logs that may be relevant and that can be done by looking at this colon transform there is a way how it's created to reverse the oper operation like as long as a Mark was created by the same log value that you are asking about you will get back the same index for example here the contract address let's say this left one is the contract address number one but we are asking about our wallet
address right so so this first one will not um decode to a valid index because we are querying with a incorrect log value but the second one um which is our wallet address um we can decode that because our query is the same log value as the one that was used to compute this Mark so once more we have our query we know the row that it pertains to we download all the filter Maps the same row that's a very efficient proof because it's always the same entry and then we go through all the marks in there and see which one of them
can we decode like for for which ones of them can we go back from the colon to a global Index this is very powerful now we have an efficient way to go from a log value all the way back to the index and the false positives are fixed by re setting this filter map every two to the 16 marks so that's like the upper bound how many false positives we can have because there can only be so many marks in a map and uh it's also like 4 million um marks that can be efficiently
filtered with just one query um because they all share the same row so there is one more missing piece here we we know that number four is interesting for our wallet but how do we know what logs corresponds to number four and for that in the IP 7745 there is also a second data structure this that is maintained and that's called a log entry it's essentially taking a hash over the log data itself and also position information about what block was it in what transaction originated this log uh if there are
multiple emits in a transaction which one of them was it so with that we can verify when we get the log later um where it was and can cross check it and also because usually when you start up a wallet it knows how far it has synced and you just care about information since your last time otherwise you have to start from Genesis every time every time that there is a new block there is also a log entry for that and with that we have a linear list that orders all the logs if we do a range query um between two blocks the server can just prove uh this is the
block delimiter the first one this is the end so you know the exact range of maps that could affect you you download the rows in those maps that um could be relevant for your wallet and that way with just like one megabyte of data that you have to download you can um get all the locks with um that affect your wallet for the entire history of ethereum so far this is implemented in go ethereum as well like there is a branch from Schult that does all of this so this gives us a secure way to to um to verify the
logs for both uh correctness and completion there is one detail that's still missing which is for the eth balance itself the eth balance is not a smart contract it's just the native um eth token so when it's sent because there is no code that's run um there is also no transfer log for it and there is another EIP to just have it do that like whenever e is transfer just treated the same as any other erc20 except instead of a contract address we just put a magic value here
for the system address but in the end it behaves the same this is important for smart contract wallets that transfer e um because uh like otherwise you may miss those logs like you send something from that wallet you don't have a log then then your history doesn't add up to your balance with this complete history for users and then likewise for validator operators that run their own notes and stake there is a similar problem that the rewards that you get for staking are currently not uh part of the log so this is another EIP to just
add logs for priority rewards and also the withdrawals that you get like in a new field and with that we can verify the entire um data that's displayed in the wallet the balance the tokens and also the history there is still more missing like when you click around in the wallet maybe you want to see the transaction details um those are covered by other eips that I won't talk about today but all of this is available as a devet like uh where you can play with it's based on Nimbus and ethereum JS there is also the web3
purifier from A6 z/ Helios and we have resources for developers like those efficiency eips that I mentioned before the cortosis config and also guides for um um building your own purifier or your own wallet link is over there all right uh that's it for this session um if there are any questions uh please right now yes incom transfers which is not which is e transfer how can you get trans uh for an incoming transfer
incoming e transfer incoming e transfer um that's this EIP here 7708 um this one means that whenever there is an incoming e transfer and your wallet is here in this two address right and because it now emits a log we can use this um the filtering mechanism from before like you just query for your own address and here your address is still part of this map right okay next questiony
hisory I I just um yes that's fine that's about one megabyte of data that you only need like if you if you know like what is your query you you you can deduce like what row you need it's only one row in this filter and by the way these filters also work on on the existing implementations there is just no commitment on chain today but if you use go ethereum they use this mechanism to accelerate the
ansers so if you ask them e get logs all of it it's very fast like seconds for for the entire history about one megabyte of data any more questions all right thanks for coming here and if you use wallets please tell them purified web 3 they can use it like every other RPC but uh they get a secure response from this like there is nothing else
they have to change um and also portal Network for this decentralized archive node instead of a centralized server all right thank you