SAT solving – An alternative to brute force Bitcoin mining (2013)
jheusser.github.io
jheusser.github.io
SAT solving typically relies on reducing a function down to boolean expressions where clauses are minimally connected with AND operations (a.k.a. Conjunctive Normal Form).
The math basis for this is that in GF2 (Galois Field 2 - a number system with only 2 values):
AND is equivalent to Multiply (1 * 1 = 1; 1 * 0 = 0, etc.)
XOR is equivalent to Addition (1 + 1 = 0; 0 + 1 = 1, etc.)
This is useful because we can re-express a boolean function as multiplication and addition for complexity analysis.The difficulty comes when you mix AND and XORs; take the Ch function within SHA256 -
Ch(E, F, G) == (E & F) | (~E & G)
Which can be rewritten as: Ch(E, F, G) == (((F ^ G) & E) ^ F)
Rewritten in GF2 it is equivalent to: Ch(E, F, G) == ((F + G) * E) + F
Because of distributive laws, we know there is zero way to simplify this further.Its trivial to see that to work backwards, you have to "consider" way more input combinations for every known output. Even if the output is 0 (which you want when Bitcoin mining), you have this problem where there are 4 possible input combinations.
Now unroll the entire SHA256d function Bitcoin uses and you realize the effort to work backwards is far more than the effort to brute-force the input keyspace. This explosion in complexity comes from the fact that the whole function feeds forward, so there is little that can be done to "resolve out" intermediate values as there are no cyclic value dependencies.
SHA256d is effectively a giant rat's nest of multiplies and adds, all stacked on top of each other, that cannot be reduced, due to distributive laws.
I don't think it's the Ch function itself (and the rest of the compression function) that causes problems for the SAT solver. I think it's the combination of the compression function and the message schedule that does it. If the message schedule had just been free variables (or simple repetitions of the message), I'm pretty sure the SAT solver would be able to unwind the compression function just fine.
The problem is the interaction between the message schedule and the compression function; once you commit to a value in some round of the compression function, you actually impose a set of constraints on the message schedule for all the other rounds simultaneously. So in a way, committing to a value in some round of the compression function means you're also indirectly influencing the possible values in every other round too. It creates this weird sort of dependency between the rounds which wouldn't exist if you only had a long series of Ch functions.
Is that actually true or did I just bs myself?
GF32 addition in GF2 basically looks like a giant ripple-carry-adder.
I tried to implement addition in GF32 through Kogge-Stone adder because the dependency chain has length 5 instead of 32. No success. The intermediate variables got so complex that the BDD library I used at the time couldn't even synthesize the expression for a 32-bit adder.
Proof of concept of the SAT solving idea.
I was curios if anyone here is mining bitcoins and if it's worth their time.
Now that we have ASICs and scammy companies with months of lead time making them, things are way more volatile. Power is cheap, but the hardware is thousands of dollars, and the preorder/crowdfunding scheme is pretty reprehensible.
Would scrypt with harder parameters make a better ASIC-resistant hash?
This is very misleading. 99.99999999% of the work of finding a valid block is finding the right block header to mine on. You have 2^32 possible nonces, and your odds of finding a block are 1 in 2^67.
By giving his program the block in advance, he's taking a shortcut.
An algorithm that could quickly decide whether a block header contained a valid solution would be very valuable indeed.
(edit: actually not fewer variables, but... I'm not sure what the correct term is, but the tree of operations gets smaller, because more results have to be fixed)
However, by fixing a variable (and effectively removing it), you are also removing potential solutions from that search space.
In a sense, you could view the difficulty of a SAT problem as the fraction of valid solutions in the whole search space. By fixing a variable, you are decreasing both the number of valid solutions and the size of the total search space. But the fraction could end up being either greater or smaller, depending on the variable and the value you set it to.
"A very intriguing, and perhaps unintuitive property of the algorithm proposed is that with increasing bitcoin difficulty, or equally lower target, the search could become more efficient, at least in theory. This is because we can assume more about the structure of a valid hash -- a lower target means more leading zeros which are assumed to be zero in the SAT-based algorithm."
This is actually pretty misleading. There might be fewer variables, but that's irrelevant. Yes, there are actually fewer variables in the actual file you feed to the SAT solver because you can assume they are 0 and propagate that to the other constraints involving those variables. But think about it -- you're only going to get rid of a couple of hundred variables at most, in a problem with ~250,000 variables. So you're only really reducing the full search space by an incredibly small percentage.
In practice, the running time of the SAT solver increases exponentially with the number of zeros you assume in the hash, just like it does for a regular brute force trying all combinations of inputs.
The conclusion I draw from this is that not all variables contribute equally to the difficulty of a problem (for a SAT solver). This is actually why SAT solvers can be efficient for some problems in the first place, even for problems with hundreds of thousands of variables; the SAT solver (a smart brute force, as opposed to a naive brute force) is able to exploit the fact that many problems you feed to it are not intrinsically hard.
In the extreme case, where we require no zeros, the problem is trivial (just hash any old data), and any good SAT solver will finish fairly quickly (perhaps with a little guidance). If we require all zeros, we are effectively asking the solver to break SHA2, which no SAT solver is going to do well at at present, or the forseeable future.
While assigning variables does decrease the worst-case complexity, no number of zeroes can be brute forced by exhaustive search before the heat death of the universe, and assigning zeroes makes finding solutions harder in a search problem which is still massive.
It can be wise to use a SAT solver to find a preimage of, e.g., SHA-256 reduced to 10 rounds. But it will be hopeless on the full function, unless it is severely broken.
If you additionally consider how SAT solving algorithms work, they are less amenable to modern CPUs than plain bruteforce, which can take full advantage of SIMD and instruction parallelism. If you look at password hash breakers, you will see them using extra tricks, like early abort, to speed things up even further.
Our hash functions are not perfect with respect to this.