I am exploring Rootstock to build a permissionless censorship resistant identity system, that differs from RNS in that it doesn’t allow users to select their own names preventing name squatting and doesn’t need to pay rent, you own your “name” forever.
That is not perfect for all usecases, but it basically gives the web a permissionless alternative to “phone numbers”, in that they are short, memorable, easy to say out loud, but hopefully (thanks to Rootstock) we can also have key recovery and make self-custody’s UX very simple.
Anyways, I was hoping I can find some guidance for how to prepare the smart contract to be as friendly to the plans of stateless clients as possible, because I value stateless clients and want to be ready for it.
Additionally, what is the best way to download the state of the contract, and read it offline, just to prepare for a future where I can’t resolve the state from any public nodes?
Storing information in Rootstock contract storage it easy once you implement functions to read Rootstock’s unitrie.
To download a known part of a contract you could use eth_getProof() to get storage proofs. However, I don’t see this function active in the current release.
There are a couple of implementations, one very recent, but I don’t know why it hasn’t been merged into rskj.
Check this:
To download all the state of a contract you would need an implementation of debug_storageRangeAt() in Roostock reference node, but I cannot find any right now.
Regarding using the 5x5 pattern to identify users: do you have a write-up of the method you use to map addresses to patterns ?
I don’t have a writeup but I can try to explain it quickly;
I try to add randomness using “Feistel network with 4 rounds” to basically do a reversible hashing with no collision.
I take the resulting u64 number and convert it to two number as follows:
pub(crate) fn encode(&self) -> String {
let val = self.0;
let mut result = String::with_capacity(17); // 8 + '-' + 8
encode_word((val >> 20) & MASK_20, &mut result);
result.push('-');
encode_word(val & MASK_20, &mut result);
result
}
Each number then is encoded as a word, using lookup tables:
/// Encode a 20-bit value into 8 ASCII characters: PREFIX + VOWEL_P + SUFFIX + VOWEL_S.
fn encode_word(bits: u64, out: &mut String) {
let hi = (bits >> 10) & 0x3FF; // top 10 bits
let lo = bits & 0x3FF; // bottom 10 bits
out.push_str(PREFIXES[(hi >> 2) as usize]); // prefix_idx: bits[9..2]
out.push(PREFIX_EXTRA_VOWEL[(hi & 0x3) as usize] as char); // vowel_p: bits[1..0]
out.push_str(SUFFIXES[(lo >> 2) as usize]); // suffix_idx: bits[9..2]
out.push(SUFFIX_EXTRA_VOWEL[(lo & 0x3) as usize] as char); // vowel_s: bits[1..0]
}
The tables are available in the source code in the HTML file I shared above, but they are basically a modified version of Urbit names prefix and suffixes, but I add one of four vowels to each prefix or suffix to get extra 256 variations in total. Urbit supports 2^32 * 256 that gives me 2^40.
I am more comfortable in Rust and barely know in Java, I am also trying to work my way from the very basics (syncing headers, calculating difficulty with all the uncles complexity, and just finding good test cases to confirm I am doing the correct thing)… once I am done with that I will try to reverse engineer the state trie, and then I might contribute.
I don’t think I would feel comfortable until I know how to build the things I need in Rust from scratch, and frankly I think this initiative is extremely necessary for Rootstock, because my impression is that you are the main person who both understand and are willing to discuss the low level details of Rootstock, and while that is ok for Defi developers, if anyone wants to bet the future of their hard work on the longevity of Rootstock, they will need more of that. In fact that is the main friction that I face trying to convince Bitcoiners to use Rootstock as we are very unlikely to repeat its bridge and merge mining success; most are not comfortable with how much they don’t understand about it, especially with the EVM overhead.
My mission is to prove (to myself at least) is that ignoring the EVM, the headers, PoW, and state are all solid. Then I will probably push as hard as I can to revive the Syncchain, because I want the best sidechain possible before it too ossify right after Bitcoin. I imagine a future wher Rootstock becomes a defacto extension of Bitcoin, and only used for expressivity and fast blocks, but many more L3s are built on top of it for scale. We can’t have that when Rootstock is hard to understand.
Ugh I just realized you mean the Go board not the name encoding…
well these are 5*5 go board, with the center and corners always empty, leaving 20 positions, and they can be either Empty, White piece, Black piece or an extra made up Black piece with a white circle, so that is 4^20 which is equal to my range of 2^40
I just go through these position and set their variant according to the binary of the number that the name encodes, where each two bits represent a variant.
Given a board, how hard is to generate a binary number that results in a very similar board (kind of a 1st pre-image attack).
How hard it is to find two binary numbers that result in very similar boards ? (kind of a 2nd pre-image attack)
I think 40 bits it’s too low to protect from these brute-force attacks, unless you do 2^30 iterations of a hash function as a Key Derivation Function (KDF) (also known as “key streching”).
The icon was for fun and not really for security. But I want to note this system isn’t really meant to be brute-forceable… the numbers are supposed to come from a Rootstock smart contract, where you call the contract, and get assigned 256 numbers mapped to your RSK address (so you can transfer some of these numbers offchain and help onboarding users that trust you temporarily before doing key rotation for full sovereignty), and the plan is to rate limit this so more or less 256 numbers are issued per Rootstock block… so it would take 1000 years or so to exhaust the numbers. But then thanks to the “Feistel network with 4 rounds”, consecutive ordinal numbers are converted to another form of numbers “permuted” that uniformly distribute them across the 2^40 space.
So if you really want to find a name and board that is very close to a famous name and board, you can of course, but you might need to wait for a century or two.
Please let me know if my logic is broken
Note: I won’t need to store 256 ordinals => address in the smart contract, I can store ranges, then overrides when someone gets one of the ordinals within a range to a different address.
Note2: I initially planned to do everything off-chain and use Rootstock only for ordering and rate limiting, but do computation and state storage offchain, but that would have been too hard especially that key management is guaranteed to be more flexible in Rootstock, and this is an important use case that justifies depending on a chain.
Note3: I usually try to avoid blockchains (I designed https://pkarr.org which depends only on Mainline DHT) but now I want to do more, namely short names and key rotation/recovery, which I concluded after a lot exploration of design space, that it needs a blockchain, and after considering L1 spacechains, I figured Rootstock is my best option, and I am basically betting that it will be able to scale, in the very offchain that this name system becomes THE sovereign name system for the internet… at least I know Rootstock have inherent reasons to pursue scale.