Pages:
Author

Topic: [ANN][COMB] Haircomb - Quantum proof, anonymity and more - page 6. (Read 6890 times)

jr. member
Activity: 76
Merit: 8
Some more thoughts:

1. I just used whitespace as syntax because that's what I'm used to, it makes more sense to use brackets IMO.

2. Modifying the AMOUNT from within an object's run() is moronic, that's a function that needs to be 100% under the control of the Haircomb Client; you'd PayTo(dest, amount) from object_A, and then the dest object would get its AMOUNT credited by Haircomb and then run.

3. I think it makes the most sense to modify all inherent variables using a native function.

Modified Liquidity Stack example:

Code:
build(int256, int256, int64)
run(int64){
if (AMOUNT > struct[2]){
execute([struct[0], struct[1], struct[2]])
                }
}

execute(args){
PayTo(args[1], args[2])
SetActive(FALSE)
ConnectTo(args[0])
        }
     

I think it makes sense to include the amount that was paid to the Object as an argument in run(), as it opens the doors for contracts that could be based on the size of an individual payment.

While it's impossible to actually calculate the cost of committing a contract yet as there's a lot to be worked out with what information the interpreter would need or not need, looking at the Liquidity Stack code you can get a guess of 69 commitments total.
jr. member
Activity: 76
Merit: 8
I've been thinking a lot about how to avoid hard forks in the future, and I might have a solution. It's too early to tell. The problem with backwards compatibility in Haircomb is that it's impossible with a system based on static smart contracts; if a client doesn't have the smart contract for a history, they can't import it. How do you provide new code to a Haircomb client, while also keeping it completely anonymous, and only ever speaking with the BTC chain??


Do

This is a theory demonstration for Do, a programming language that consists of smart contract code hidden within the BTC blockchain. This fork to introduce Do would introduce a new wallet entry /type, /contract. When a wallet runs into the /contract code, it would check to see if it currently had the contract code compiled in its database. If it did not, it would find the contract code, located on the BTC block chain, and pull and compile it. It could then process and understand the transaction. The methodology for storing Do on the BTC chain is as follows.

1. Write a Do contract. The contracts can be written using native functions that are contained within every Haircomb client, such as math functions, SHA256, or GetCommit related functions. They can also be written by referencing other custom contracts that have been created.

2. Get the contract's ID. This is created by concatenating a nonce and the script of the contract.

3. Build the commits necessary to commit the code to the BTC chain. It's easier to show an example than to explain:

Code:
ID = SHA256(  NONCE if A > B:  )
code commits:
SHA256(ID + if + 0)
SHA256(ID + A + 1)
SHA256(ID + > + 2)
SHA256(ID + B + 3)
SHA256(ID + DO + 4)
SHA256(ID + END + 5)

While it is obviously incomplete code, you can see the commit process in action. Concatenate the contract ID, the chunk, and the chunk index, then SHA256.

4. Once the contract commits have been generated, commit them to the BTC chain. They must be committed in index order.

5. When a Haircomb client that does not know this script receives a TX history that contains it, it searches for the location of the contract ID on the chain. This marks the beginning of the contract. Haircomb then begins checking each consecutive P2WSH address in the BTC chain, and for each one it check if the address = SHA256(ID + WORD + INDEX) The ID is the contract ID, the INDEX is the current chunk index, and the WORD is the current keyword that is being checked. It runs this script for each keyword it knows, on each P2WSH, until it finds a correct answer. In the above example it would find that SHA256(ID + if + 0) == currently tested address. Then it adds 1 to the INDEX value, and repeats. It does this until it finds the WORD END, at which point it knows the script has finished.

In order to embed contracts within other contract code, we can't reference them by ID. If we did, Haircomb would never be able to guess them, because their ID is a random 256bit number. Instead, we can reference them using a native function called BuildGetObject(index, args). Index is the index of the contract ID, and args is an array with the arguments used to build that function when the code is actually being processed (I'll explain shortly). Because all Haircomb nodes know BuildGetObject, they know that the first argument of BuildGetObject will be the index of an Object they need to get.  NOTE: During this reading, if you see a reference to another object written during build func as simply something like Object(args), know that in practice it would be committed as BuildGetObject(index, [object_args]).

I'll refer to the main script as a Contract, and the thing it creates during processing as an Object. Some rules for Objects:

Objects have variable CONNECT_TO, it is an address, if any, that their funds flow into down the chain
Objects have variable ACTIVE, when active if they are payed funds they call their run(), if inactive they pay the funds to their CONNECT_TO address and skip their run() code.
Objects have an AMOUNT, which is how much COMB they currently have stored. Only relevant in some cases
Objects are built in build code by referencing their Contract ID location on chain, and are run in run code by referencing the individual instance of the built object.
If an Object finishes run() and it has a CONNECT_TO address, it automatically sends all of its funds there.

Some example of native functions might be:
Code:
SHA256(content):
returns the hash of content

GetCommitHeight(address):
returns the height of the address, if it exists. If not, return 0

GetCommitIndex(address):
returns the index of the address if it exists. If not, return 0

GetCommitsByHeight(height, height):
returns all unseen P2WSH in between the two heights

GetCommitsByIndex(index, index):
returns all unseen P2WSH in between the two indices.

PayTo(dest, amount):
Subtracts amount on funds and puts them in the destination. If the dest.AMOUNT < amount, this function will NOT fire. Not needed on
        standard, 100% payments, just use CONNECT_TO

BuildGetObject(index, [args]):
Gets the ID of the references contract, and if it isn't already compiled in storage, compile it. Then build with it. Store with its index.

A bunch of Math functions (+, /, >, etc.)

Note: This next part I'm sketchy about, as I don't know if Haircomb uses temporal methodology like I have laid out here, or if it uses an algorithmic, atemporal process. If it does though, I have 0 idea how it deals with liquidity stacks then, but if I can figure it out I can easily convert this into an atemporal system. A temporal system feels like it'd be super slow, so I'm hoping I'm wrong here

When a wallet is processing a TX history, first it initializes the all the transactions in the history as objects. Next, it spawns the combbase. As the comb trickles into an object, it will trigger the run(x) function, where X = the amount of comb that has entered the object. Once the object's run() has completed, if the comb can trickle further it will, trigger more run(), until finally it cannot trickle any more. Then the next combase will trickle, and so on, until no comb can trickle further.

I have built some already existing and or theorized Haircomb contracts to show an example. When I use the syntax struct, I am referring to an array of values that is created directly from the build() function arguments. Struct as in structure.

1. Liquidity Stack
Code:
build(int256, int256, int64) #change_add, send_add, send_threshold)
run(int64):
AMOUNT += run[0]     # Increase stored amount
if AMOUNT > struct[2]:     # If stored > threshold
execute([struct[0], struct[1], struct[2], AMOUNT])     # send COMB

execute(args):
PayTo(args[1], args[2])
ACTIVE = FALSE
CONNECT_TO = args[0]

2. Hot Cash Address (Decider is built with left_object, tip1, tip2)
Code:
build(int256, Decider.build(int256, int256, int256), [int16, int256, int256])     # Fallback, decider(), longdecider, unCAT
run(int64):
AMOUNT += run[0]
if struct[1].run(struct[2]):     # If signature checks out
if struct[2][0] == 0:
execute(struct[0])     # If signed 0, fallback
else:
execute(struct[2][0])     # Go forward

execute(args):
CONNECT_TO(args[0])
ACTIVE = FALSE

3. Lock
Code:
build(int256)
run(commit):     # commits are sent as [commit, index]
if SHA256(run[0][0]) == struct[0]:     # If key
execute([TRUE])

execute(args):
return args[0]

4. TimedLockbox
Code:
build([int256, int256], [Lock.build(keyhash), Lock.build(keyhash)], int32, int32))
run(int64):
AMOUNT += run[0]
for commit in GetCommits(struct[2], struct[3]):
if struct[1][0].run(commit[0]):     # Run NO Lock with commit[0], if NO key found
for this_commit in GetCommits(commit[1], commit[1]):     # Check for YES in rest of block
if struct[1][1].run(this_commit[0]):     # If YES in same block
execute(struct[0][1])     # YES
else:
execute([struct[0][0]])     # NO
elif struct[1][1].run(commit[0]):     # Run YES Lock with commit[0], if YES key found
if not commit[1] > struct[2]+1):     # If not greater than first block
execute(struct[0][1])
else:
for this_commit in GetCommits(struct[2]+1, commit[1]-1):     # Check prev height commits
if struct[1][0].run(this_commit[0]):     # IF NO before
execute(struct[0][0])     # NO
else:
execute(struct[0][1]  )   # YES

execute(args):
CONNECT_TO = args[0]
ACTIVE = FALSE

I'm not a good enough coder to know if this'll work yet. But it seems like the logic is there. If we can break everything down into tiny pieces, we can open up the door for completely open-sourced creativity. Anybody could make any contract they wanted to, and if they completely mess up, they'd just be losing their money. And if we did it right, there'd never need to be a fork again.

Let me know how you think this could be attacked or exploited. I don't know enough yet to know if this will really work, but thinking about what it could accomplish if it did makes me want to try.
jr. member
Activity: 76
Merit: 8
That's a pretty cool way to de-couple destinations from their direct address, using block order. It's slower than Turbines (unless my walkthrough is incorrect), and more expensive, but the fact that you can do it solo and aren't merging TX histories with everybody in the cycle is a huge upside, not to mention the potential problems of a Turbine going down in an ecosystem that's still building to multiple Turbine options. The fact that no infrastructure is required is huge.  What do you think about centralized wallets in general, hard fork or not? I feel like if they're an inevitability due to the convenience and 0 TX fees, not everybody cares about security and privacy, and that it makes sense to try and make options for them that are as secure and convenient as possible.

Looking at the current extrapolation of Haircomb with no forks, if you agree that Turbines would be inevitable then we're looking at

a) 4 commits per semi-safe transaction (My_Funds->My_Decider(Store Here), My_Funds->Oracle_Decider, Turbine_Funds->My_Destination, Oracle_Decider_Funds->Turbine.)
b) 2 commits per less-safe transaction (My_Funds->Oracle_Decider(Store Here), Turbine_Funds->My_Destination, Oracle_Decider_Funds->Turbine.)
c) 0 commits per not-safe transaction (Permanent Turbine Storage).

So the core ecosystem would require trust to participate on a frequent basis. I think that forks make sense in this case, introducing other options could go a long way.

Do you think there's a way that, if forked, we could update Haircomb without needing to fork again? The problem is ofc that a wallet needs to process every transaction in the chain, so backwards compatibility can't work like BTC, but do you think there's a way to circumnavigate it? I have some ideas but they aren't mature yet.

EDIT: Thinking about it more, I really can't stress enough the benefit of 0 infrastructure. Turbines will take AGES to get up and running properly, and they'll rely extremely heavily on the surrounding environment. Hot Cashes Addresses will be way easier to implement, and helping bridge the gap to the point that Turbines are actually working will be enormous. And even then, if you value your independence the extra fee may very well be worth it, depending on the price.
sr. member
Activity: 682
Merit: 268
If hard fork is an option, I think the same basic goal of reducing the 21 addresses in many cases can be reached differently:

Hot cash address.

Hot cash address can be SHA calculated from a secret fallback address and an enough decider to sign 16 bits.

Hot cash address operation.

If the user signs 16 bit signed number zero the system flows the coins from the hot cash address to the fallback.

If the user signs a non zero value n: the money will flow to the n-th address that was commited to on chain
after the fallback address was commited to on chain. (or before if n is negative)


Hot cash paying

1. the user who owns funds on a hot cash address commits the fallback address to the chain to start the relative offset period.
2. the user commits the liquidity stack commitment where the user wishes to pay.
.. wait 6 confirmations ...
3. the user subtracts the relative positions of the two previous commitments: n = position2 - position1, and signs n, if n fits in a 16 bit signed int.
.. wait 6 confirmations ...
4. funds are now paid to the liquidity stack.


This would cost 4 addresses funded per hot cash cycle.


Possible problems:
 - the user does not wait 6 confirmations & attacker manipulates the relative order
   - result: all funds stolen
   - solution: wait longer
 - the attacker manipulates the order to make the distance |n| greater than 32767
   - by inserting your 2 commitments into their transaction(s) that confirm before yours and in which the values are more apart
   - result: transaction does not go through
   - solution: sign 0 to go to fallback / replace by fee outbid the attacker



The advantage could then be that the user needs not to approach another player in the form of turbine, can do everything purely alone.

jr. member
Activity: 76
Merit: 8
I've combined the above three posts into an idea. If this works, it would reduce the cost of transacting on the BTC chain from 21 transactions down to (21+X)/X, where X is the amount of transactions being batched together. It would also be done in a completely trustless manner, without the use of third parties. First I will establish the two new COMB objects that are required to make this work. Note: It is possible to accomplish the same structure of motion in the current system, however it costs (21+2X)/X, and relies on trusting a 3rd party.


Objects Required

-- Witness
A Witness would operate similarly to the previously described Witnesses. This Witness would act as a Paired Witness, but rather than being paired up with another, corresponded Witness, it would be targeting something called a Lockbox. The information a Witness would require is a forward address, a rollback address, and the target address (the address of the Lockbox it is Witnessing)

-- Lockbox
A Lockbox will operate similarly to the previously described Paired Witness, in the manner that it uses the same Lock/Key system that the Paired Witness uses. You can think of it as essentially a mini Decider; rather than 65355 destinations, a Lockbox has 2. Because the Lockbox only has 2, we can sign the Lockbox using a single commit. The Lockbox would be made up of a forward address, a rollback address, two locks, a YES lock, a NO lock, the height of the BTC block at which the Lockbox becomes valid, and optionally the height of a BTC block that the Lockbox expires on. To unlock a Lockbox, the controller would commit one of the two keys to the BTC chain. If the controller commits both Keys, the Key that appears on the first BTC block will be considered valid. If they both appear on the same block, then YES lock will be considered valid. If a Key appears on the blockchain before the stated start_block, it will be discounted, and only the other Key will be a valid commit. If an expiry block is specified and subsequently reached without any keys being committed, it will act as a NO key sign.


Walkthrough

A Client wishes to send funds using a turbine. They send their funds to a Lockbox, the address of which is built from SHA256(turbine_1, client_2, yes_lock, no_lock, start_height, expiry_height) . The Client then sends their transaction history to the Turbine, proving that their funds have been deposited into lockbox_1. First, if the current BTC height is greater than the stated start_height, the Turbine most check each of the previous blocks between then and now, to confirm that a Key has not already been signed during this time. The Turbine then creates a Witness, built from SHA256(client_2, turbine_2, lockbox_1). The Turbine deposits the same amount of funds into witness_1 that the Client has deposited into lockbox_1, and sends the Client the information proving it. Once this has been establish on the Client's end, the Client commits lockbox_1's YES key to the BTC chain. Due to the ease of calculation, whether the Client ends up being a good guy and sharing the information with the Turbine is irrelevant, the Turbine should be able to deduce the the Lockbox's status simply by trying P2WSH addresses from the BTC chain until one fits the lock, and then trying the rest of the Keys on the block until it can confirm that 1 or two keys were committed on this block, and can move forwards from there.

Here is a diagram of the process: https://i.imgur.com/TR67aWN.png


You may say that this does not reduce costs, because a Client must pay to put their funds into the Lockbox. However, this only needs to happen once, on initial Turbine cycle entry. They can specify a Turbine address, and no matter how many cycles go by before they initiate a contract with the Turbine, the funds will always flow to the currently active Turbine wallet. When a Client initiates a contract with a Turbine, they can specify that they want the destination of their funds to be a Liquidity Stack, the OUT address being a payment they wish to make, but the CHANGE address being directed to ANOTHER Lockbox. The Client should also specify a Merkle tree as the output of their Lockboxes, one that has options to go to other Turbines in case there's a problem with this one in the future, or to a private wallet as a final backup measure. By chaining Lockboxes together, after the initial transaction from a Private Wallet to a Lockbox, each additional transaction will only require one BTC commit, so long as the Client continues to go Lockbox->Turbine->Lockbox->Turbine. Each cycle that they participate in, they have the opportunity to make payments.


One hiccup in the scheme is that a Client will no longer be able to receive funds or claim COMB on their old, private wallets. They will have to give other parties the address of the current lockbox they are waiting in, and once they initiate an atomic swap with a Turbine they will have to begin receiving funds into the new Lockbox address.

Another potential weakness, albeit an odd one, is if a malicious Client decides to suicide-bomb the Turbine. If the Client deposits X funds into a Lockbox with no expiry height, and the Turbine then deposits X funds into a Witness targeting that Lockbox, the Client has the option of just never signed either key. This will cause both the Turbine and the Client to lose access to X funds. The Turbine can avoid this possibility however, if it decides to only accept contracts with people who's funds are in a Lockbox that has a defined expiry height.


I don't know if this will work yet, because there are areas of operation that I am not currently educated enough on to understand. Will this require too much processing? The amount can be reduced by storing the Key's address with the history of the lockbox in the wallet, once the operation has been concluded, however future wallets would need to confirm that the other key was not signed in between the start height of the contract and the height of the committed Key. I also don't know enough about the processing of COMB objects internally, i.e. why Decider/Contracts use different number system. I'm assuming it's because they are not supposed to have COMB deposited into them, and so it differentiates them from addresses that ae supposed to have COMB deposited into them, but I'm not sure, so it's a variable I have to consider.


If, however, this WOULD work, it would open up a ton of possibilities I think. The fact that you could have multiple Witnesses all witnessing a single Lockbox seems like it would be a VERY powerful tool, though I have not thought about how it could be used yet.

If anybody can confirm or deny that this would work, I would appreciate it.

jr. member
Activity: 76
Merit: 8
The idea I had before to circumvent the problem didn't pan out, but I think I have a different solution. Rather than use a Decider/Contract and a Witness, you would use two Paired Witnesses. The Paired Witnesses would also utilize a hash based lock and key, where SHA256(key) = lock.

A Paired Witness would be constructed using the following steps.

1. pwit_id = SHA256(forward, rollback, lock)

2. address = SHA256(pwit_id, target)

In place of the target you would fill in the other Witness ID in the pairing, i.e. pwit1_add = SHA256(pwit1_id, pwit2_id), pwit2_add = SHA256(pwit2_id, pwit1_id)

The information that both parties would get, in addition to the transaction info proving the counterparty's deposit of funds into the counterparty's generated pwit_address, would be the information making up the counterparty's pwit_address, i.e. forward, rollback, lock, and target. A user could then confirm that the counterparty had deposited funds into the address that was Paired with their Witness. In order to unlock a Witness, the Witness's Key must be committed to the BTC chain, as well as the key to the other Witness that it has been paired with. Due to the simplicity of the lock, it would be easy to determine the key just by looking at the committed P2WSH addresses on the BTC chain if the counterparty decided not to send you the TX information proving that they had committed the Key. And said counterparty MUST commit the key, because otherwise their funds remain in the Witness.

Currently the structure doesn't use the rollback address, however it can be used if you give either party a method of terminating the swap. The first method that comes to mind would be using another lock and key, and detecting which one came first on the BTC chain, but there are certainly others, and I haven't thought about which would be better.

Let me know if something I've described wouldn't work.
jr. member
Activity: 76
Merit: 8
I've been thinking a lot about how to remove a 3rd party from COMB/COMB swaps, and while I can get close, I can't figure out a way to solve one final issue.

The methodology I've been using relies on adding a new object type to the programming of COMB. Right now I'm calling them Witnesses. The way a Witness would function is similar to a Decider/Contract, however rather than trigger based off of the Decider signing a number to determine the destination of the funds, a Witness would trigger off of witnessing another event take place. Let me explain via example.

Alice and Bob want to perform a COMB for COMB swap. Alice first creates a Decider/Contract (dc_1) where she is the decider, and the contract addresses are: forward = bob_2, rollback = alice_2. Alice pays her COMB into dc_1, and then sends Bob the transaction history proving that the Decider/Contract is valid and that she has funded it. Bob then creates a Witness. I haven't figured out the exact syntax yet, but it would need to include a forward address, a rollback address, and the object address that it was witnessing. In this case those details would be forward = alice_2, rollback = bob_2, and witnessing = dc_1. Bob then pays his COMB into witness_1. Bob sends his transaction history to Alice. Alice then sees that a witness_1 is both funded and is witnessing dc_1. She now decides dc_1 as FORWARD.

When she decides dc_1, she commits the sign number to the BTC chain in the form of the two bc1 addresses. If I'm not missing anything, the Witness will be able to see this, and verify, using the information that Alice has, that dc_1 has been signed FORWARD, and will ALSO act as if it has been signed forward. This will release the funds on witness_1 into alice_2. Then Alice sends the TX history to Bob, and once he has it he'll have enough information to verify how the Decider was signed, and he'll get the funds out of the Decider.

There's a problem though. What if Alice is an asshole, and decides to just not give Bob the TX history after she's signed the Decider and gotten the COMB out of the Witness? She doesn't actually gain anything extra from this, but a malicious actor could screw over their counter-party by dong this.

This is the problem I don't have a good solution to. However, there may bee some financial trickery that can get "around" this problem. I'll make a post a little later once I've fleshed it out. Also keep in mind I have no idea of the feasibility or mathematically implications of including more objects into the Haircomb code. If I've missed any potential problems here, let me know.
jr. member
Activity: 76
Merit: 8
I just learned about the centralized wallets. Natasha is a genius. Giant economic pumps, driving comb through them to run the payment system, with people using deciders as their wallets. But Watashi, my friend, I realized you are wondrously wrong about something!

Quote
instead of providing 65536 different addresses as the 65536 leaves wich are useless from the business perspective

This is true if you are a person who is deciding a contract for other people. But what if you are a person deciding a contract for YOURSELF???

Rather than send the funds from the pump to a decider with only 2 options(1 back to the Pump and 1 back to your private wallet) you could have a contract with 65536 options! You could include multiple different pump options, in case the one you normally used happened to rugpull, or even just go down temporarily for some reason. You could have multiple leaves with different liquidity stack combinations of payments you might have to make in the future (this one is a bit of a stretch, but it works well for repeated, static cost events, stuff like going to a physical therapist).

But then I realized something else. These pumps can be automated! They can be completely automated, through the use of decider contracts!!! A pump would have a certain threshold of funds that it could accommodate, for example lets say a specific Pump can accommodate 10000 COMB. This Pump would have to keep 10000 COMB on it to maintain operation. A Client would then approach the Pump and tell it that they wanted to send X COMB to a location, via the Pump. They would also approach a third party, also an automated system, to facilitate the contract as the Contractor. The Contractor would communicate with the Pump and the Client, and build a contract that would send the stored funds either to the Pump, or back to the Client. The Client pays the COMB into the contract. Once the contract has been funded, the Pump then runs its next cycle, and pays the same amount of COMB that's in the contract to the address the Client wanted it sent to. Once the Contractor gets the transaction history from the Pump and verifies that the funds have in fact gone to the specified location, it Decides the contract in favour of the Pump.

If the Client doesn't pay the contract, the Pump just doesn't send the COMB to the address. If the Pump doesn't send the comb to the address, the Contractor decides in favour of the client, and the funds go to the clients backup address!!! The Pump can only accept the amount of COMB in contacts per cycle that it has on hand, as it's required to prepay all the contracts before they'd be settled in the Pump's favour.

Let me know if I've fucked anything up. I think this'll work. The integration with the BTC chain means that you wouldn't even have to rely on an oracle system I think. Let me know if I've gone full schizo here lol.

EDIT: I can't make up my mind about which sounds better, Pump or Turbine. Pump is more apt mechanically, but, as it was pointed out to me, isn't great in a financial connotation. Turbine also suggests automation, whereas Pump does not, and Turbine sounds grandiose and cool.
jr. member
Activity: 76
Merit: 8
There is an unanswered question about Alice spending coins before she received them, it comes as a surprise
to an ordinary Bitcoiner, that you can even do this (and it definitely looks like a money creation from thin
air problem at first sight).

The scenario is spending a 0 COMB key and paying out say 1 COMB to your friend using the liquidity
stack output and then later (optionally) funding that 0 COMB key with 1 COMB.

Why there is no pay button for 0 COMB keys?

because it seems pointless spending 0 COMB. You can access the underlying URL manually and then you can then spend 0 COMB keys.

Why can't I pay out 2 COMB from a 1 COMB key? Or pay out 1 COMB from a 0 COMB key?

This is a safeguard to prevent users from accidentally having their money stuck in a pending liquidity stack.

If users can bypass these checks, why there is not a money creation from thin air problem at the consensus layer?

Because haircomb money must be created from comb-base only. If you spend a 0 COMB key paying
out a 1 COMB to your friend, he sees that there is no comb-base associated that filled the original
wallet with 1 COMB in the history given to the friend.
In effect the friend will see no incoming funds at all until the comb rules are full-filled. They will be full-filled when
the history is merged with another history paying the reuqired funds from comb-base.
It does not matter who merges the histories, or in what order the histories were made, it only matters that
the final merged history gets posted to the final recipient somehow.

So yes, in effect, you can spend funds before you have them. But they will only become available to the final
party only at the moment they get paid to you and the histories get merged and posted to the final party.

Ok this makes sense and lines up with what I understood; the wallet is essentially building the plumbing of the wallet on every boot and spawning the coins in their claimed addresses, then seeing where they end up. Pre-connecting B->C before A->B won't show any funds in C, because there weren't any in B. Once you connect A->B, then they'll show in C.

Quote
It's pretty uninteresting (to be honest), so let's change the topic to comb trades.

Preliminaries: Comb trades use 16-level-65536-leaf merkle tree as a building block. They also use a decider as a building block. Merkle
tree is well understood, but I need to explain decider.

It is a postquantum signature scheme to sign a small number 0-65535.

Basically you roll 2 256bit true random numbers, and you save them carefully on disk. That is the decider private key. That private key can also
be stored in-wallet.

From the private key you calculate two hash chains of 65535 hashes. Then you hash 3 values one of which is just 256bit zero. This is a chaining
value to be explained later. Currently you can assume it will be zero. The other two values are the tips of the hash chains.

So you hash the 3 values and you get a "decider public key" also known as "short decider." You can give the short decider to other people.
It is like an address except it isn't, it is hexadecimal 256 bit number but uses different alphabet G-V

The user received a short decider from the decider person. The user wants to make the contract address.

To make the contract address just hash "short decider" CAT "merkle root".

This makes sense, it's what I understood from the whitepaper, just like a normal transaction.

Quote
WHAT MERKLE LEAVES TO USE

There is a trick, instead of providing 65536 different addresses as the 65536 leaves wich are useless from the business perspective
the user uses just a "forward" address and a "rollback" address repeatedly. These kinds of binary contracts with exactly 2 outcomes
are important for all kinds of trades.

So to fill the 65536 leaves of the merkle tree the user uses a pattern of just 2 addresses. There are 16 useful patterns. They are:

1. rollback (1 time), forward (1 time), rollback (1 time), forward (1 time), ... (total 65536 times)
2. rollback, rollback (2 times), forward, forward (2 times), ... (total 65536 times)
3. rollback, rollback, rollback, rollback  (4 times), forward, forward, forward, forward (4 times)... (total 65536 times)
...
...
...
16. rollback (32768 times), forward (32768 times) (total 65536 times)

The counter-party also does the same calculation to arrive at the exactly same merkle root. And because both parties trust the decider
person, they both use the decider person's "short decider", to arrive and cross-check the exact contract address.

These patterns each have the additional property, that, if you are flipping just 1 bit, exactly one comb-trade-bit's outcome is changing.

Holy crap.

Quote
So imagine you sign the 16bit number to be "1" instead of "0" what happens? Only in the pattern 1 the outcome (the leaf address) changed from
rollback to forward. Other contracts remain unaffected (remain "rollback").

This is why 16 comb trade bits exist, this is how 1 decider is able to control up to 16 binary comb trades between 32 trading parties, to be settled
at the same time.


Obviously you can simply use 1 decider for 1 comb trade. Using 1 decider for 16 contracts is just an optimalization to squeeze more commerce into
Bitcoin's tiny block space.

So essentially the infrastructure exists to combine an large amount of 3rd-party trades into a single operation. That's awesome.

Quote
You (the decider person) can sign using the decider just you would with a haircomb, that is, you commit-to from the two hash-chains
a commitments of two values at the depths that sums to 65535.
If you fail to do this, you will burn the key, e.g. the scheme is one-time-only.

Then you (or somebody) tips the two commitments using 330 sats.

When there are 6+ confirmations you can reveal the "signature" also known as a "long decider"

The signature is just a signed value n (16-bit) CAT value at depth n CAT value at depth 65535-n in some encoding.

Ok so the long decider isn't just the hashchain heads of the short decider then, that makes sense. Do you think that the signed value n needed to be included in the signature? Couldn't you determine that value based on the other 2 signature values? I guess that it doesn't really matter if you include the signed value N, but it saves computing power on the wallet side, so it makes sense to include it.

Quote
The user adds the proof that the decider had signed a number n together with a proof of n-th merkle branch to their wallet. The wallet
accepts the combined proof as a coin history entry and moves the funds from the contract address to the merkle leaf address.

The leaf address can be again one of the 3 address types e.g. haircomb public key/liquidity stack entry/contract address.

But the leaf address can also be another merkle root, this is the chained merkle tree scenario in which the decider is not hashed
with the 256 bit zero but with another chained short decider to form a linked list of deciders.

To extend the amount of contracts that can be signed exponentially, while only increasing the amount of commitments needed linearly? If I'm understanding that correctly, it's hilarious and amazing.

EDIT: I may be wrong on the above statement? I need to spend more time visualizing the expansion process, it's difficult to do. My gut thought now though is that it would just double the amount of contracts available, but if that's the case then why would you even bother stacking trees like that?

EDIT2: Thinking about it more it makes sense that it's exponential. A tree with 4 tips can hold 2 patterns, a tree with 16 tips can hold 4, if the pattern threshold is just the square root of the tip count (not sqrt, po2 I guess)  then my initial assumption was correct. That's crazy.

One question and then I'll walk through an applied example to make sure I'm not missing anything. The following quote:
Quote
To make the contract address just hash "short decider" CAT "merkle root".

If the decider person wanted to sign multiple contracts at the same time, then the user wouldn't be the person choosing the Merkle Tree pattern, correct? It would have to be the decider person, to make sure that all the contracts they were deciding were all on different bits, right?

Okay so walkthrough time:

Alice wants to send COMB to Bob, and Cindy wants to send COMB to Dan. Xavier will be the decider person. Alice, Bob, Cindy, and Dan all give Xavier their addresses; Alice=Rollback_1, Bob=Forward_1,  Cindy=Rollback_2, Dan=Rollback_2. As there are only 2 contracts being decided, there's no need for nested Merkle Trees, so Xavier generates the two Decider private keys and then gives the Short_Decider (000...000 CAT hashchain_tip_1 CAT hashchaintip_2) Alice, Bob, Cindy, and Dan. He also generates 2 Merkle Trees, one for Alice and Bob's contract (Tree_AB) and one for Cindy and Dan's contract (Tree_CD), and gives them to their respective participants. They then each generate the COMB Address that their contract's Sender will deposit COMB into, for Alice and Bob it's SHA256(Short_Decider CAT Tree_AB) and for Cindy and Dan its SHA256(Short_Decider CAT Tree_CD). Tree_AB is using pattern 1 (01010101...) and Tree_CD is using pattern 2 (00110011...)

Alice and Cindy both deposit their COMB into their respective contract addresses, eager to get their shitcoins. I'll go over each of the possibilities below. (Using N min = 0, max = 65535:

1. Bob and Dan both deposit their shitcoins, as requested: Xavier signs N=3, Tree_AB = 010(1)... and Tree_CD = 001(1)..., COMB goes to Forward_1 and Forward_2

2. Bob loses his shitcoin wallet keys, but Dan makes his shitcoin deposit: Xavier signs N=2, Tree_AB = 01(0)1... and Tree_CD = 00(1)1..., COMB goes to Rollback_1, Forward_2

3. Bob deposits his shitcoins, but Dan accidently sends all his shitcoins to a scammer: Xavier signs N=1, Tree_AB = 0(1)01... and Tree_CD = 0(0)11..., COMB goes to Forward_1, Rollback_2

4. Bob and Dan both listen to Elon Musk and buy DOGE instead: Xavier signs N=0, Tree_AB = (0)101... and Tree_CD = (0)011..., COMB goes to Rollback_1, Rollback_2

Is this correct?

P.S. It's good to hear from you again, thank you Smiley
sr. member
Activity: 682
Merit: 268
There is an unanswered question about Alice spending coins before she received them, it comes as a surprise
to an ordinary Bitcoiner, that you can even do this (and it definitely looks like a money creation from thin
air problem at first sight).

The scenario is spending a 0 COMB key and paying out say 1 COMB to your friend using the liquidity
stack output and then later (optionally) funding that 0 COMB key with 1 COMB.

Why there is no pay button for 0 COMB keys?

because it seems pointless spending 0 COMB. You can access the underlying URL manually and then you can then spend 0 COMB keys.

Why can't I pay out 2 COMB from a 1 COMB key? Or pay out 1 COMB from a 0 COMB key?

This is a safeguard to prevent users from accidentally having their money stuck in a pending liquidity stack.

If users can bypass these checks, why there is not a money creation from thin air problem at the consensus layer?

Because haircomb money must be created from comb-base only. If you spend a 0 COMB key paying
out a 1 COMB to your friend, he sees that there is no comb-base associated that filled the original
wallet with 1 COMB in the history given to the friend.
In effect the friend will see no incoming funds at all until the comb rules are full-filled. They will be full-filled when
the history is merged with another history paying the reuqired funds from comb-base.
It does not matter who merges the histories, or in what order the histories were made, it only matters that
the final merged history gets posted to the final recipient somehow.

So yes, in effect, you can spend funds before you have them. But they will only become available to the final
party only at the moment they get paid to you and the histories get merged and posted to the final party.

It's pretty uninteresting (to be honest), so let's change the topic to comb trades.

Preliminaries: Comb trades use 16-level-65536-leaf merkle tree as a building block. They also use a decider as a building block. Merkle
tree is well understood, but I need to explain decider.

It is a postquantum signature scheme to sign a small number 0-65535.

Basically you roll 2 256bit true random numbers, and you save them carefully on disk. That is the decider private key. That private key can also
be stored in-wallet.

From the private key you calculate two hash chains of 65535 hashes. Then you hash 3 values one of which is just 256bit zero. This is a chaining
value to be explained later. Currently you can assume it will be zero. The other two values are the tips of the hash chains.

So you hash the 3 values and you get a "decider public key" also known as "short decider." You can give the short decider to other people.
It is like an address except it isn't, it is hexadecimal 256 bit number but uses different alphabet G-V

The user received a short decider from the decider person. The user wants to make the contract address.

To make the contract address just hash "short decider" CAT "merkle root".

WHAT MERKLE LEAVES TO USE

There is a trick, instead of providing 65536 different addresses as the 65536 leaves wich are useless from the business perspective
the user uses just a "forward" address and a "rollback" address repeatedly. These kinds of binary contracts with exactly 2 outcomes
are important for all kinds of trades.

So to fill the 65536 leaves of the merkle tree the user uses a pattern of just 2 addresses. There are 16 useful patterns. They are:

1. rollback (1 time), forward (1 time), rollback (1 time), forward (1 time), ... (total 65536 times)
2. rollback, rollback (2 times), forward, forward (2 times), ... (total 65536 times)
3. rollback, rollback, rollback, rollback  (4 times), forward, forward, forward, forward (4 times)... (total 65536 times)
...
...
...
16. rollback (32768 times), forward (32768 times) (total 65536 times)

The counter-party also does the same calculation to arrive at the exactly same merkle root. And because both parties trust the decider
person, they both use the decider person's "short decider", to arrive and cross-check the exact contract address.

These patterns each have the additional property, that, if you are flipping just 1 bit, exactly one comb-trade-bit's outcome is changing.

So imagine you sign the 16bit number to be "1" instead of "0" what happens? Only in the pattern 1 the outcome (the leaf address) changed from
rollback to forward. Other contracts remain unaffected (remain "rollback").

This is why 16 comb trade bits exist, this is how 1 decider is able to control up to 16 binary comb trades between 32 trading parties, to be settled
at the same time.


Obviously you can simply use 1 decider for 1 comb trade. Using 1 decider for 16 contracts is just an optimalization to squeeze more commerce into
Bitcoin's tiny block space.


You (the decider person) can sign using the decider just you would with a haircomb, that is, you commit-to from the two hash-chains
a commitments of two values at the depths that sums to 65535.
If you fail to do this, you will burn the key, e.g. the scheme is one-time-only.

Then you (or somebody) tips the two commitments using 330 sats.

When there are 6+ confirmations you can reveal the "signature" also known as a "long decider"

The signature is just a signed value n (16-bit) CAT value at depth n CAT value at depth 65535-n in some encoding.

The user adds the proof that the decider had signed a number n together with a proof of n-th merkle branch to their wallet. The wallet
accepts the combined proof as a coin history entry and moves the funds from the contract address to the merkle leaf address.

The leaf address can be again one of the 3 address types e.g. haircomb public key/liquidity stack entry/contract address.

But the leaf address can also be another merkle root, this is the chained merkle tree scenario in which the decider is not hashed
with the 256 bit zero but with another chained short decider to form a linked list of deciders.

jr. member
Activity: 76
Merit: 8
I've been trying to figure out exactly how the deciders and contracts function mechanistically. Below I've included a diagram of my current understanding of the structure of the two, which I believe is correct. (This is of a non-stacked object, hence the "000...000")



I'm stuck on how the actual mechanism works. I don't understand how Natasha managed to sign multiple contracts with the same decider. This is even more perplexing when you look at her post in which she states:

Quote
- I will publish a file with say 1000 deciders in it. This will mean I could theoretically decide 1000 comb trade contracts

This makes me think you can decide more contracts than 1 using the same decider, so long as you decide them all simultaneously. But I don't understand how that would work. My assumption is that as the decider, you're committing 2 numbers to the BTC chain; the hashchain CCW() results for both of the long decider numbers. But unless you where structuring the associated merkle trees in such a manner that the same two commits would trigger all of them simultaneously to respond the way you wanted, I don't see how that's possible.

My other assumption was that, looking at the image I posted, the short decider is either SHA256(000...000 + N_1 + N_2), or just SHA256(N_1 + N_2).

Another thing I don't understand is the need for the merkle tree. The wallet only lets you input 2 addresses for each contract; the Forward Address and the Rollback address. Is this just a limitation of the current wallet design, which can be expanded upon to include all 65536 destinations in a single contract?
jr. member
Activity: 76
Merit: 8
RakeCOMB v0.2.0 is out.
https://github.com/nixed18/RakeCOMB/releases/tag/v0.2.0

Changes:
Add the ability to perform transactions and view previous transaction information.

There are some modifications to how RakeCOMB performs when compared with HaircombCore; RakeCOMB prevents you from using a previously burnt address as the Change Address for future transactions. I can't think why this wouldn't be appropriate, but if I've missed something, let me know.
jr. member
Activity: 76
Merit: 8
I finally had some time to work on a GUI over the past week.

RakeCOMB v0.1.0 can be found here: https://github.com/nixed18/RakeCOMB

Current Functionality:
 - Save and Import wallets
 - Receive transfers
 - Browse accounts and stealth addresses
 - Generate new accounts
 - Incomplete commits validation
 - Safe shutdown

Place the exe and then pck in the same folder as your .dat files so the Import can detect them.
Transaction initiation and TX History browsing are planned for the next version. Let me know if you have any thoughts.

Also, if anybody can identify what font Natasha used in her first post's infographic, I'd appreciate it
newbie
Activity: 4
Merit: 0
Made a telegram for COMB for those interested. t.me/comb_talk
jr. member
Activity: 76
Merit: 8
I have a couple questions about the way the coin history and wallet work.

1. If I receive comb to a stealth address that's already been swept, the wallet realize this and automatically drop the comb in my main wallet, or should I never reuse a stealth address like this?

2. Related to the previous, if Bob sends comb to Cindy, and then Alice sends comb to Bob's old wallet, can she just give the coin history to Cindy and have it transfer into Cindy's wallet? I realize this is an odd process that would most likely never occur organically, but it's interesting to think about.

EDIT: Looking into the way that the wallet files are store, it seems like the answer to the first question is yes, it would work to receive at previously swept addresses, however I'm still not sure about the second question's answer.
legendary
Activity: 1517
Merit: 1042
@notsofast
Hi

Haircomb on litecoin is a possibility, it will be a separate coin (only on Litecoin assuming that's what you want).

I will just briefly write what is the minimal effort you need to do in order to kickstart such a coin.

First of all you need a white paper preferably you put some recent LTC block-hash into the
whitepaper to prevent a premine.

Briefly explain in your whitepaper the subsidy formula at minimum so that people at least
know how many tokens they claimed by a valid claim on a block.

You can code any subsidy formula in coinbase.go just recode the Coinbase(height uint64) function.

Just make sure there is not some kind of numeric overflow in 64bit monetary amount when you add too many subsidies to one wallet.

Next take SHA256(whitepaper.pdf) and put that into commitment.go file.

Next to actually claim you need to modify bech32get in sign.go to match litecoin format. I think just change "bc" to "ltc"

Recompile combfullui.exe

Next you can start modifying litecoin core. You need to modify it in the same manner the Natasha
modified bitcoin core.

Each time a block is added to a litecoin longest valid chain you need to call (for every long ltc address in the block)
the following endpoint of haircomb core.

http://127.0.0.1:2121/mining/mine/{commit}/{utxotag}

also at the end of block you need to call it one more time to flush it.

The flush comand has arbitrary 256bit commit (for instance FFFFFF... it's not used for anything) but it must have utxotag = 9999999999999999

You can be loading the commitments in the following manner:

suppose there was address funded on litecoin chain:

ltc1qguz6pay8hvv0qsd07wtptcfx5wjxa8tqququgurlvm2yfaj9txqsn8xsdv

mined for example in block 1673450

Now when your litecoin core adds this block to his longest valid chain the above address (output) in hex:

00204705a0f487bb18f041aff39615e126a3a46e9d600701c4707f66d444f6455981

you discard the 0020 from the beginning and call over http (also it needs to be uppercase because Natasha hated lowercase):

http://127.0.0.1:2121/mining/mine/4705A0F487BB18F041AFF39615E126A3A46E9D600701C4707F66D444F6455981/0167345000000001

the 00000001 at the end is some kind of iterator I think recent combfullui.exe after fork does not even use it for anything so
you can supply 0,1,2,3 from the block or whatever (which one long address inside the block it was) it just must be unique

then you flush it:

http://127.0.0.1:2121/mining/mine/FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/9999999999999999


and now this commitment appears in the litecoin commits.db file (but only if the address was funded the 1st time!) and triggers
any transactions in the wallet that require it.

But you need to be loading blocks in the correct order obviously. You can't load block 123 and then 122.

Recompile litecoin core and sync it.

Go into your wallet generate a key and claim some litecomb. Fully save your wallet. Good luck.


Now there are many ways that can go wrong if this gets widely used and I don't actually encourage to do this.

For instance somebody can pay from litecomb key and somebody can replay that payment to haircomb on bitcoin.
secondly people can confuse addresses, pay litecomb to normal haircomb address and get glued coins
the coin can pump and dump and never recover causing financial loss
and many more things

but it will work for experimental purposes.


Cool, thank you for taking the time to explain how this would be done. It's beyond my coding ability but I will try to work through the process and see how far I get.
sr. member
Activity: 682
Merit: 268
Hi

Haircomb on litecoin is a possibility, it will be a separate coin (only on Litecoin assuming that's what you want).

I will just briefly write what is the minimal effort you need to do in order to kickstart such a coin.

First of all you need a white paper preferably you put some recent LTC block-hash into the
whitepaper to prevent a premine.

Briefly explain in your whitepaper the subsidy formula at minimum so that people at least
know how many tokens they claimed by a valid claim on a block.

You can code any subsidy formula in coinbase.go just recode the Coinbase(height uint64) function.

Just make sure there is not some kind of numeric overflow in 64bit monetary amount when you add too many subsidies to one wallet.

Next take SHA256(whitepaper.pdf) and put that into commitment.go file.

Next to actually claim you need to modify bech32get in sign.go to match litecoin format. I think just change "bc" to "ltc"

Recompile combfullui.exe

Next you can start modifying litecoin core. You need to modify it in the same manner the Natasha
modified bitcoin core.

Each time a block is added to a litecoin longest valid chain you need to call (for every long ltc address in the block)
the following endpoint of haircomb core.

http://127.0.0.1:2121/mining/mine/{commit}/{utxotag}

also at the end of block you need to call it one more time to flush it.

The flush comand has arbitrary 256bit commit (for instance FFFFFF... it's not used for anything) but it must have utxotag = 9999999999999999

You can be loading the commitments in the following manner:

suppose there was address funded on litecoin chain:

ltc1qguz6pay8hvv0qsd07wtptcfx5wjxa8tqququgurlvm2yfaj9txqsn8xsdv

mined for example in block 1673450

Now when your litecoin core adds this block to his longest valid chain the above address (output) in hex:

00204705a0f487bb18f041aff39615e126a3a46e9d600701c4707f66d444f6455981

you discard the 0020 from the beginning and call over http (also it needs to be uppercase because Natasha hated lowercase):

http://127.0.0.1:2121/mining/mine/4705A0F487BB18F041AFF39615E126A3A46E9D600701C4707F66D444F6455981/0167345000000001

the 00000001 at the end is some kind of iterator I think recent combfullui.exe after fork does not even use it for anything so
you can supply 0,1,2,3 from the block or whatever (which one long address inside the block it was) it just must be unique

then you flush it:

http://127.0.0.1:2121/mining/mine/FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/9999999999999999


and now this commitment appears in the litecoin commits.db file (but only if the address was funded the 1st time!) and triggers
any transactions in the wallet that require it.

But you need to be loading blocks in the correct order obviously. You can't load block 123 and then 122.

Recompile litecoin core and sync it.

Go into your wallet generate a key and claim some litecomb. Fully save your wallet. Good luck.


Now there are many ways that can go wrong if this gets widely used and I don't actually encourage to do this.

For instance somebody can pay from litecomb key and somebody can replay that payment to haircomb on bitcoin.
secondly people can confuse addresses, pay litecomb to normal haircomb address and get glued coins
the coin can pump and dump and never recover causing financial loss
and many more things

but it will work for experimental purposes.
jr. member
Activity: 76
Merit: 8

I can't tell right away, but would BTC-comb be compatible with LTC-comb? Could it be made compatible?

I think technically it could, but you'd have to run a full node of both chains at the same time. I'm not sure on how the claiming process would have to adapt though.
legendary
Activity: 1517
Merit: 1042
@notsofast
Hello boys. The project is alive. I'm working on the liquidity stack loops. It will be done when the numbers tell me it's done and not earlier.

I'm working on it in my spare time and I am not paid but that is not the problem. Money won't accelerate the progress only brain power will. I feel that my coins going up in value eventually will be the best reward.

Yeah you have to outbid highest fee payer.

About the possibility of haircomb on BSV or on BCH, it's not directly possible since there is no segwit and thus no 256bit addresses that I am aware of.

Even if those coins had 256bit addresses it would be a not so great idea to run haircomb on it. The reason is it uses sha256 hashing and is prone to 51%/reorg attacks. And succesfull 51 % attack means recently-transacted coin destruction in the worst case (if the attacking miner knows the haircomb coins history)

Haircomb on Litecoin would be a possibility though, it's reasonably powerful, has segwit, and not prone to 51% attacks.

I'm very interested in running haircomb on Litecoin. What would it take for a port?

From a practical standpoint, it would make a much lower and more reasonable price acquisition floor for comb.

I can't tell right away, but would BTC-comb be compatible with LTC-comb? Could it be made compatible?
jr. member
Activity: 76
Merit: 8

this helps miners because in the event that in the future their btc rewards are very small, comb rewards might be bigger then the btc reward. (if comb actually gets adoption) this can help miners incentivize and keep securing btc.
another good point is because claiming comb or sending comb burns btc. it creates a deflation on btc and rising the value of btc slowly too.


This is a really good point, the fact that you'd essentially be taking pressure off of the BTC economy and fees by having haircomb be a reward in a symbiotic relationship, that's really interesting. I was looking at the claim monopoly as a bad thing, but this makes sense in the wider environment when you include bitcoin.
Pages:
Jump to: