jl777 (OP)
Legendary
Offline
Activity: 1176
Merit: 1134
|
|
May 23, 2016, 06:13:15 PM |
|
I am finally close to finishing the iguanacore, the RPC layer is going through testing and so far all bugs found have been easy to fix.
So I am back to debugging the atomic swap and now have the state machine going through 80% of the process, but I am doing it in a loopback mode for now so I dont have to wait for new blocks and can just use the same unspents over and over for testing.
One issue with fully decentralized exchange is that people will lose their connections and the need to properly resume a pending trade needs to be solved. Assuming a power loss, then any temporary keypairs would need to be preserved so the funds can be properly claimed. Worst case is if a powerloss causes HDD corruption and you are in the protocol phase where you need the keys to claim it, you are losing funds.
So, this means a robust key storage and recovery mechanism is needed.
Or is it?
What I came up with is a deterministic keypairs system that allows recreating all temporary keys used for a specific swap, using just the accounts main keypair. I am assuming that proper care about backing up the main keypair is done.
Since there is a lot of divulging of the temporary keypairs going on, I wanted to make sure that neither the main keypair is compromised and also that this method doesnt open up an attack vector. I am thinking that since it has algebraic structure, it makes things a bit harder to spoof, but I cant see any direct way of the other party verifying things directly.
Here is the process:
bits256 instantdex_derivekeypair(struct supernet_info *myinfo,bits256 *newprivp,uint8_t pubkey[33],bits256 privkey,bits256 orderhash) { bits256 sharedsecret; sharedsecret = curve25519_shared(privkey,orderhash); vcalc_sha256cat(newprivp->bytes,orderhash.bytes,sizeof(orderhash),sharedsecret.bytes,sizeof(sharedsecret)); return(bitcoin_pubkey33(myinfo->ctx,pubkey,*newprivp)); }
A chain of keypairs are generated that starts from the main account keypair and that one needs to be protected. Each iteration of the chain uses the derivekeypair function. The orderhash is SHA256 of the orderbook entry that is being swapped. I am using the nodes orderbook entry, but maybe it is better to use the other party's entry, or a combine value. Probably the combined value is best, that way the keypairs chain is only for the exact swap.
The first step is to make a shared secret using the orderbook hash as the "pubkey" and the main account's privkey as the privkey. The curve25519 is used for speed and it does an SHA256 of the actual shared secret field element, so that protects the main privkey as well as curve25519 + SHA256 does.
This shared secret is put through another round of SHA256 with the orderhash and that is used as the privkey to generate an secp256k1 pubkey. There is a small chance of failure here as not all 256bit value are valid privkeys, but that is taken care of with the outer loop.
The outer loop does the following: for (n=0; n<keypairs_needed; n++) { pubi = instantdex_derivekeypair(myinfo,&swap->privkeys[n],pubkey,privkey,hash); privkey = swap->privkeys[n]; if ( pubkey[0] != firstbyte ) continue; ... }
the first iteration, the privkey is the main account privkey, but after each iteration, the privkey is what is calculated in the prior iteration. Since each new privkey requires a shared secret using the main privkey, only the owner of that privkey is able to generate each iteration.
Also, I set all of Bob's privkey's so that the pubkey starts with 0x03 and Alice's starts with 0x02. that allows to use it as an extra consistency check and with the libsecp256k1 library, the time it takes is not really noticeable for generating about double the keypairs. this check also catches the case where the privkey is illegal as the first byte will be 0x00
Now comes the part I think might have some issues the part above that is in the "..."
calc_rmd160_sha256(secret160,swap->privkeys[n].bytes,sizeof(swap->privkeys[n])); memcpy(&txid,secret160,sizeof(txid)); len += iguana_rwnum(1,(uint8_t *)&swap->deck[m][0],sizeof(txid),&txid); len += iguana_rwnum(1,(uint8_t *)&swap->deck[m][1],sizeof(pubi.txid),&pubi.txid); m++;
txid is a unit64_t and it is the lower 64bits of the bits256. I calculate both the rmd160+sha256 of the privkey and also the lower 64bits of the secp256k1 pubkey. These are the cut and choose keypairs that are sent to the other side. and all but the chosen one is sent back in full privkey form so the above uint64's can be verified.
maybe there is no need to send both variants and just one will suffice, but I have a feeling that with this additional constraint, it might be possible to get some proof that the chosen keypair is valid, prior to funds being committed via pederson commitments or something like that.
James
|