kTimesG
Member
![*](https://bitcointalk.org/Themes/custom1/images/star.gif)
Offline
Activity: 101
Merit: 24
|
![](https://bitcointalk.org/Themes/custom1/images/post/xx.gif) |
Today at 02:32:42 PM Last edit: Today at 02:46:09 PM by kTimesG Merited by albert0bsd (2) |
|
You can use nomachine's Rust Kangaroo a few posts back, or write a Python script that does the job according to your requirements (e.g. "that actually works"). Too slow? Well, don't expect to find something that "actually works", is fast, and solves 130, sitting out there for you to snug up and inherit 13 BTC tomorrow.
Not in Rust. Pure C++ with GMP. Here is the latest version that goes 470K Hops per second. Theoretically, with 12 cores, it can achieve 5 million hops per second. The more cores you have, the better the result will be. However, it's not worth using this for a puzzle above 70bit. A GPU must be used instead.... Pure self-contained Python Kangaroo with no libraries required. 225K Hops per second. DO NOT USE THIS TO SEARCH FOR 130. It is just an educational, reference-only example. All the math uses Python integers. kangaroo.py import math, os, sys, time
class S: # Scalar field N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
@staticmethod def add(a, b): return (a + b) % S.N
class F: # Curve field P = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f
@staticmethod def add(a, b): return (a + b) % F.P
@staticmethod def mul(a, b): return (a * b) % F.P
@staticmethod def pow(b, e): return pow(b, e, F.P)
@staticmethod def sqrt(a): return F.pow(a, (F.P + 1) // 4)
@staticmethod def inv(a): if a == 0: return 0
r = 1 s = 0 low = a % F.P high = F.P
while low > 1: q = high // low nm = s - q * r nw = high - low * q high = low s = r low = nw r = nm
return r % F.P
class Point: # Affine point def __init__(self, x, y, parity=-1): self.x = x self.y = y if parity == -1 else Point.calc_y(x, parity)
@classmethod def uncompress(cls, s): parity, xh = int(s[:2], 16), s[2:] if parity not in [2, 3]: raise Exception("Expected parity 02 or 03") return Point(int(xh, 16), 0, parity % 2)
@staticmethod def calc_y(x, parity): y = F.sqrt(F.add(F.pow(x, 3), 7)) # y = sqrt(x**3 + 7) return y if parity == y % 2 else F.P - y
class JPoint: # Jacobian point def __init__(self, x, y, z): self.x = x self.y = y self.z = z
def affine(self): z = F.inv(self.z) z2 = F.mul(z, z) return Point(F.mul(self.x, z2), F.mul(self.y, F.mul(z, z2)))
def mul(self, n): if self.y == 0 or n == 0: return JPoint(0, 0, 1)
if n == 1: return self
if n < 0 or n >= S.N: return self.mul(n % S.N)
if (n % 2) == 0: return self.mul(n // 2).double()
return self.mul(n // 2).double().add(self)
def double(self): if self.y == 0: return JPoint(0, 0, 0)
y2 = F.mul(self.y, self.y) s = F.mul(4 * self.x, y2) M = F.mul(3 * self.x, self.x)
x = F.add(F.mul(M, M), - 2 * s) return JPoint(x, F.add(F.mul(M, s - x), -F.mul(8 * y2, y2)), F.mul(2 * self.y, self.z))
def add(self, q): if self.y == 0: return q if q.y == 0: return self
qz2 = F.mul(q.z, q.z) pz2 = F.mul(self.z, self.z) U1 = F.mul(self.x, qz2) U2 = F.mul(q.x, pz2) S1 = F.mul(self.y, F.mul(q.z, qz2)) S2 = F.mul(q.y, F.mul(self.z, pz2))
if U1 == U2: if S1 != S2: return JPoint(0, 0, 1) return self.double()
H = F.add(U2, -U1) R = F.add(S2, -S1) H2 = F.mul(H, H) H3 = F.mul(H, H2) U1H2 = F.mul(U1, H2) nx = F.add(F.mul(R, R), -F.add(H3, 2 * U1H2)) ny = F.add(F.mul(R, F.add(U1H2, -nx)), -F.mul(S1, H3)) nz = F.mul(H * self.z, q.z)
return JPoint(nx, ny, nz)
class Group: G = Point( 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 )
@staticmethod def add(p, q): m = F.mul(F.add(p.y, -q.y), F.inv(F.add(p.x, -q.x))) x = F.add(F.add(F.mul(m, m), -p.x), -q.x) return Point(x, F.add(F.mul(m, F.add(q.x, -x)), -q.y))
@classmethod def mul(cls, p, k): # [k]P point scalar multiplication return JPoint(p.x, p.y, 1).mul(k).affine()
@classmethod def batch_add(cls, ga, gb): n = len(ga) d = [0] * n p = [0] * n z = 1 for i in range(n): d[i] = F.add(ga[i].x, -gb[i].x) z = F.mul(z, d[i]) p[i] = z
t = F.inv(z)
for i in range(n - 1, -1, -1): if i > 0: xi = F.mul(t, p[i - 1]) t = F.mul(t, d[i]) else: xi = t
m = F.mul(F.add(ga[i].y, -gb[i].y), xi) ga[i].x = F.add(F.add(F.mul(m, m), -ga[i].x), -gb[i].x) ga[i].y = F.add(F.mul(m, F.add(gb[i].x, -ga[i].x)), -gb[i].y)
class TrueRandom: def __init__(self, max_value: int, num_bits: int, min_value: int = 0): self.upper_bound = max_value - min_value + 1 self.min = min_value self.num_bits = num_bits self.domain = 2 ** num_bits self.num_bytes = math.ceil(num_bits / 8) self.shift = 8 * self.num_bytes - num_bits
def get_next(self): random_bytes = os.urandom(self.num_bytes)
# trim to num_bits random_int = int.from_bytes(random_bytes, byteorder='big') >> self.shift
# normalize from domain range to target range sample = self.upper_bound * random_int // self.domain
return sample + self.min
def kangaroo_with_results(k1, k2, P, dp, herd_size): k_cand, counter, tbl_size = kangaroo(k1, k2, P, dp, herd_size=herd_size)
k = k_cand[0] if k1 <= k <= k2: P_check = Group.mul(Group.G, k) if P_check.x == P.x: print(f'Key: {hex(k)}\nGroup ops: {counter}')
return k_cand, counter, tbl_size
def create_kangaroo(kang_type, pos: int, herd_pts, herd_distances, k1, k2, P, rnd: TrueRandom, v): if kang_type == 0: # d = rnd.get_next() # [0, k2 - k1) d = (k2 - k1 + 1) + pos * v # b/2 + i*v # d = (k2 - k1 + 1) // 2 herd_distances[pos] = d herd_pts[pos] = Group.mul(Group.G, k1 + d) else: # d = rnd.get_next() - (k2 - k1 + 1) // 2 # [-(k2-k1)/2, (k2-k1)/2] d = (k2 - k1 + 1) // 2 + pos * v # b + i*v # d = 0 herd_distances[pos] = d herd_pts[pos] = Group.add(P, Group.mul(Group.G, d))
def check_col(kang_type, hashmap, herd, dist, pos, k1, k2, P, dp_mask, R, v_rnd, respawn_dead=True, stop_at_dp=True): x = herd[pos].x
if x & dp_mask == 0: item = hashmap.get(x)
if item is not None: if item[0] == kang_type ^ 1: # collision d_wild, d_tame = (item[1], dist[pos]) if kang_type == 0 else (dist[pos], item[1]) return [S.add(k1 + d_tame, - d_wild)], 0 else: # print(f'Dead kangaroo at {pos}') if respawn_dead: # create_kangaroo(kang_type, pos, herd, dist, k1, k2, P, R) # move along with a small random value d = v_rnd.get_next() dist[pos] += d herd[pos] = Group.add(herd[pos], Group.mul(Group.G, d))
# this will recurse until a non-dead kangaroo is produced k, created = check_col(kang_type, hashmap, herd, dist, pos, k1, k2, P, dp_mask, R, v_rnd) return k, 1 + created else: hashmap[x] = (kang_type, dist[pos])
return 0, 0
def build_jump_distances(alpha, with_points=False): jump_points = [] jump_distances = []
# compute A (jump distances) such that average(A) is closest to expected alpha # Pollard says choosing A as powers of two feels like "needs more investigation" min_diff = 1 while True: jump_distance = 2 ** len(jump_distances) jump_distances.append(jump_distance) if with_points: jump_points.append(Group.mul(Group.G, jump_distance))
alpha_real = sum(jump_distances) / len(jump_distances) diff = abs(1 - alpha_real / alpha) if alpha_real >= alpha: if diff > min_diff: jump_distances.pop() break if diff < min_diff: min_diff = diff
return jump_distances, jump_points
def kangaroo(k1, k2, P, dp: int, herd_size: int = 128): b = k2 - k1 + 1 # size of search interval m = herd_size + herd_size # m/2 + m/2 # parallel case - minimize alpha for total number of jumps alpha = m * math.sqrt(b) / 4 # m * sqrt(b) / 4
jump_distances, jump_points = build_jump_distances(alpha, with_points=True) alpha_real = sum(jump_distances) / len(jump_distances)
n = len(jump_distances)
# adjust alpha to the actual average jump distance alpha_expected = alpha alpha = alpha_real
# expected total number of jumps for each trailing kangaroo (1 per processor) expected_trailing_jumps = 2 * math.sqrt(b) / m # 2 * sqrt(b) / m
# beta = 0.553 # serial case # ab_jumps = int(alpha * beta) # serial case # max_tame_distance = int(alpha * alpha * beta + b // 2)
# expected number of jumps done by a trailing kangaroo after it enters the [b, ...] region # this would equal the number of jumps done by a tame kangaroo that starts from b num_tame_jumps = 4 * alpha / (m * m) # 4 * alpha / (m**2) max_tame_distance = int(alpha * num_tame_jumps + b) # average jump size * num jumps + start # max_wild_distance = int(alpha * num_tame_jumps + b/2) # average jump size * num jumps + start # = (2*a/m)**2 = (sqrt(b) / 2)**2
# set v to the "partition" size for a processor, and not a power of two v = b // m - 1 # (b/2) / (m/2) # v = herd_size v_rnd = TrueRandom(v, 256)
hashmap = {} wilds: list = [None] * herd_size tames: list = [None] * herd_size w_dist = [0] * herd_size t_dist = [0] * herd_size counter = 0 done_ab_jumps = 0
expected_total_jumps = math.ceil((num_tame_jumps + expected_trailing_jumps) * herd_size) print( f'processors: {m}' f'\n num jump distances: {n}' f'\nmax jumps per tame kangaroo: {math.ceil(num_tame_jumps)}' f'\nmax jumps per wild kangaroo: {math.ceil(expected_trailing_jumps)}' f'\n expected total jumps: {expected_total_jumps} {math.log2(expected_total_jumps):.2f} bits' f'\n avg real jump distance: {round(alpha_real)} {math.log2(alpha_real):.2f} bits' f'\n avg expected jump distance: {round(alpha_expected)} {math.log2(alpha_expected):.2f} bits' f'\n expected max tame distance: {max_tame_distance} {math.log2(max_tame_distance):.2f} bits' # f'\n expected max wild distance: {max_wild_distance} {math.log2(max_wild_distance):.2f} bits' )
R = TrueRandom(k2 - k1, 256, 0) dp_mask = (1 << dp) - 1
for idx in range(herd_size): create_kangaroo(0, idx, tames, t_dist, k1, k2, P, R, v) counter += 1
k, born = check_col(0, hashmap, tames, t_dist, idx, k1, k2, P, dp_mask, R, v_rnd) counter += born if k: return k, counter, len(hashmap)
create_kangaroo(1, idx, wilds, w_dist, k1, k2, P, R, v) counter += 1
k, born = check_col(1, hashmap, wilds, w_dist, idx, k1, k2, P, dp_mask, R, v_rnd) counter += born if k: return k, counter, len(hashmap)
batch_jp: list = [None] * herd_size
start_time = time.time() last_p_time = 0 while True: if done_ab_jumps < num_tame_jumps: # jump tames for idx in range(herd_size): d = tames[idx].x % n # tames[idx] = Group.add(tames[idx], jump_points[d]) # un-batched addition batch_jp[idx] = jump_points[d] t_dist[idx] += jump_distances[d]
Group.batch_add(tames, batch_jp)
for idx in range(herd_size): counter += 1
k, born = check_col(0, hashmap, tames, t_dist, idx, k1, k2, P, dp_mask, R, v_rnd) counter += born if k: return k, counter, len(hashmap)
done_ab_jumps += 1 if done_ab_jumps >= num_tame_jumps: # new_max = max(t_dist) # avg_dist = sum(t_dist) / len(t_dist) # print( # f'Tames are done.' # f'\nExpected max tame distance: {max_tame_distance} {math.log2(max_tame_distance):.2f} bits' # f'\nAverage max tame distance: {avg_dist} {math.log2(avg_dist):.2f} bits' # f'\nActual max tame distance: {new_max} {math.log2(new_max):.2f} bits' # ) # max_tame_distance = max(max_tame_distance, new_max) # max_wild_distance = int(max_tame_distance + b / 2) # add initial tame - wild gap
# create new tames herd for idx in range(herd_size): d = b + idx * v + v_rnd.get_next() # b/2 + i*v + z
t_dist[idx] = d tames[idx] = Group.mul(Group.G, k1 + d) counter += 1
done_ab_jumps = 0
for idx in range(herd_size): d = wilds[idx].x % n # wilds[idx] = Group.add(wilds[idx], jump_points[d]) # unbatched addition batch_jp[idx] = jump_points[d] w_dist[idx] += jump_distances[d]
Group.batch_add(wilds, batch_jp)
for idx in range(herd_size): counter += 1
k, born = check_col(1, hashmap, wilds, w_dist, idx, k1, k2, P, dp_mask, R, v_rnd) counter += born if k: return k, counter, len(hashmap)
if w_dist[idx] > max_tame_distance: # create_kangaroo(1, idx, wilds, w_dist, k1, k2, P, R) z = v_rnd.get_next() d = b // 2 + idx * v + z # b + i*v + z
w_dist[idx] = d wilds[idx] = Group.add(P, Group.mul(Group.G, d))
counter += 1
total_time = time.time() - start_time if total_time - last_p_time > 3: last_p_time = total_time print(f'Ops: {counter} Table size: {len(hashmap)} Speed: {counter / total_time:.0f} ops/s')
def run_puzzle(idx: int, pub_key, dp: int = 0, herd_size: int = 128, benchmark=0): # puzzle #X has (X - 1) unknown bits k1 = 1 << (idx - 1) k2 = (k1 << 1) - 1
# subtract k1 to search in a [0, k2 - k1) interval k2 -= k1 k1 = 0
P = Point.uncompress(pub_key)
# subtract (k2 - k1)G from P to bring target point's k to [0, k2 - k1) interval P = Group.add(P, Group.mul(Group.G, -(k2 + 1)))
now = time.time() _, ops, hashmap_size = kangaroo_with_results(k1, k2, P, dp, herd_size) total_time = time.time() - now print(f'Ops: {ops} Stored: {hashmap_size}') print(f'Speed: {ops / total_time:.0f} ops/s')
if __name__ == '__main__': # r, p = int(sys.argv[1]), sys.argv[2] # run_puzzle(r, p, dp=0, herd_size=128)
# run_puzzle(32, '0209c58240e50e3ba3f833c82655e8725c037a2294e14cf5d73a5df8d56159de69', # herd_size=512)
run_puzzle(48, '0291bee5cf4b14c291c650732faa166040e4c18a14731f9a930c1e87d3ec12debb', dp=8, herd_size=1024)
Puzzle 48: processors: 2048 num jump distances: 38 max jumps per tame kangaroo: 6899 max jumps per wild kangaroo: 11586 expected total jumps: 18927375 24.17 bits avg real jump distance: 7233629130 32.75 bits avg expected jump distance: 6074001000 32.50 bits expected max tame distance: 190638869267657 47.44 bits ... Ops: 17607859 Table size: 68719 Speed: 225400 ops/s Key: 0x2de6d7ce3b9b Group ops: 18288933 Ops: 18288933 Stored: 71317 Speed: 222616 ops/s
|
|
|
|
cnk1220
Newbie
Offline
Activity: 24
Merit: 0
|
![](https://bitcointalk.org/Themes/custom1/images/post/xx.gif) |
Today at 03:30:36 PM |
|
I think that kangaroos that have been forked or modded from JLp's original kangaroo do not work. and I'm really asking about kangaroo running on 125 bit and above.
how do you know it doesn't work? in this last one there is no number 125 in the code. it's all 256...there is NO way to prove it doesn't work because it's impossible to solve puzzle 130. So how do you know if it's working? Do you have proof? Many people claim that they forked and modified the original JPL kangaroo 125-bit program and created new 256-bit kangaroo programs. So do these work? What happens if there is a code error? What if it was created incorrectly? How would you feel if, after using it for months, someone told you that the program didn't really work? Let me give an example: the keyhunt bsgs program definitely works. So, is there anyone who has used the modded kangaroo program and can say this? What you mean "works"? How do YOU know keyhuntbsgs works?
|
|
|
|
albert0bsd
|
![](https://bitcointalk.org/Themes/custom1/images/post/xx.gif) |
Today at 04:03:01 PM Last edit: Today at 08:11:30 PM by albert0bsd |
|
Just for those who want to know here are all my RAWTX for the RBF challenge from some days ago and the TXID or Error code returned from the mempool API: Address 197kFKvMHoRJPXktc8xJwMjeTuE9xijBQ found public key 029fd3d2479a37f40d03975cb51ce0fa18cbb709cc46b47caeaa1722cfd3683583 Keyfound 000000000000000000000000000000000000000000000002357CAC24E9C2D41D for address 197kFKvMHoRJPXktc8xJwMjeTuE9xijBQ UXTO TXID:3ee3fa9738d6f3357966f2283c8cc9409bd24ec1033762b936152717977ce520 index 0 balance 492600
Output to bc1qcrej0q6xqfyr9ecayk3y6khykuugt7za6umuk4 with 490104 satoshis, network bitcoin Raw TX: 010000000120e57c9717271536b9623703c14ed29b40c98c3c28f2667935f3d63897fae33e000000006a473044022031f4cf9bf5a9dc03b7ee11e8f31c8d362f225b8a9db0c8ed9bce24a833d1301f02201417d3564599b67aeffd53818e004898b7f884ffc6000a691f1e9e232a4927120121029fd3d2479a37f40d03975cb51ce0fa18cbb709cc46b47caeaa1722cfd3683583ffffffff01787a070000000000160014c0f3278346024832e71d25a24d5ae4b73885f85d00000000 TXID: 7e91e4f33f6ead7ebb0d441e180a1ff0f66071b466ea3c6aab2ef9e36f4c98b3
Output to bc1qcrej0q6xqfyr9ecayk3y6khykuugt7za6umuk4 with 488856 satoshis, network bitcoin Raw TX: 010000000120e57c9717271536b9623703c14ed29b40c98c3c28f2667935f3d63897fae33e000000006a47304402200c97ff52a39e5a42907617847e979c89ff7d660f10862f8c9edd0d32e90fa17802200c74a1117890f4b8248ad0fa2a14d66e283b66732c2fd0e3a59d27d657bbb95b0121029fd3d2479a37f40d03975cb51ce0fa18cbb709cc46b47caeaa1722cfd3683583ffffffff019875070000000000160014c0f3278346024832e71d25a24d5ae4b73885f85d00000000 TXID: 5967ccefbaeee59a85c8f8689cd85684089a91a09b56b3a67d9e7845b237592c
Output to bc1qcrej0q6xqfyr9ecayk3y6khykuugt7za6umuk4 with 488856 satoshis, network bitcoin Raw TX: 010000000120e57c9717271536b9623703c14ed29b40c98c3c28f2667935f3d63897fae33e000000006a47304402200c97ff52a39e5a42907617847e979c89ff7d660f10862f8c9edd0d32e90fa17802200c74a1117890f4b8248ad0fa2a14d66e283b66732c2fd0e3a59d27d657bbb95b0121029fd3d2479a37f40d03975cb51ce0fa18cbb709cc46b47caeaa1722cfd3683583ffffffff019875070000000000160014c0f3278346024832e71d25a24d5ae4b73885f85d00000000 TXID: sendrawtransaction RPC error: {"code":-26,"message":"txn-mempool-conflict"}
Output to bc1qcrej0q6xqfyr9ecayk3y6khykuugt7za6umuk4 with 488856 satoshis, network bitcoin Raw TX: 010000000120e57c9717271536b9623703c14ed29b40c98c3c28f2667935f3d63897fae33e000000006a47304402200c97ff52a39e5a42907617847e979c89ff7d660f10862f8c9edd0d32e90fa17802200c74a1117890f4b8248ad0fa2a14d66e283b66732c2fd0e3a59d27d657bbb95b0121029fd3d2479a37f40d03975cb51ce0fa18cbb709cc46b47caeaa1722cfd3683583ffffffff019875070000000000160014c0f3278346024832e71d25a24d5ae4b73885f85d00000000 TXID: 5967ccefbaeee59a85c8f8689cd85684089a91a09b56b3a67d9e7845b237592c
Output to bc1qcrej0q6xqfyr9ecayk3y6khykuugt7za6umuk4 with 488024 satoshis, network bitcoin Raw TX: 010000000120e57c9717271536b9623703c14ed29b40c98c3c28f2667935f3d63897fae33e000000006b483045022100b6daea5a333af8f3d52134f9b4cab6a59721fcd2a23538c5e29c55d23e21d64802202c7e5799d91ff7921cc6cc3de84bc710aa9e8c9c49841b30a30f3b7e5142e65b0121029fd3d2479a37f40d03975cb51ce0fa18cbb709cc46b47caeaa1722cfd3683583ffffffff015872070000000000160014c0f3278346024832e71d25a24d5ae4b73885f85d00000000 TXID: sendrawtransaction RPC error: {"code":-26,"message":"txn-mempool-conflict"}
Output to bc1qcrej0q6xqfyr9ecayk3y6khykuugt7za6umuk4 with 488856 satoshis, network bitcoin Raw TX: 010000000120e57c9717271536b9623703c14ed29b40c98c3c28f2667935f3d63897fae33e000000006a47304402200c97ff52a39e5a42907617847e979c89ff7d660f10862f8c9edd0d32e90fa17802200c74a1117890f4b8248ad0fa2a14d66e283b66732c2fd0e3a59d27d657bbb95b0121029fd3d2479a37f40d03975cb51ce0fa18cbb709cc46b47caeaa1722cfd3683583ffffffff019875070000000000160014c0f3278346024832e71d25a24d5ae4b73885f85d00000000 TXID: sendrawtransaction RPC error: {"code":-26,"message":"insufficient fee, rejecting replacement 5967ccefbaeee59a85c8f8689cd85684089a91a09b56b3a67d9e7845b237592c; new feerate 0.00019914 BTC/kvB <= old feerate 0.00029872 BTC/kvB"}
Output to bc1qcrej0q6xqfyr9ecayk3y6khykuugt7za6umuk4 with 488856 satoshis, network bitcoin Raw TX: 010000000120e57c9717271536b9623703c14ed29b40c98c3c28f2667935f3d63897fae33e000000006a47304402200c97ff52a39e5a42907617847e979c89ff7d660f10862f8c9edd0d32e90fa17802200c74a1117890f4b8248ad0fa2a14d66e283b66732c2fd0e3a59d27d657bbb95b0121029fd3d2479a37f40d03975cb51ce0fa18cbb709cc46b47caeaa1722cfd3683583ffffffff019875070000000000160014c0f3278346024832e71d25a24d5ae4b73885f85d00000000 TXID: sendrawtransaction RPC error: {"code":-26,"message":"insufficient fee, rejecting replacement 5967ccefbaeee59a85c8f8689cd85684089a91a09b56b3a67d9e7845b237592c; new feerate 0.00019914 BTC/kvB <= old feerate 0.00044255 BTC/kvB"}
Output to bc1qcrej0q6xqfyr9ecayk3y6khykuugt7za6umuk4 with 488856 satoshis, network bitcoin Raw TX: 010000000120e57c9717271536b9623703c14ed29b40c98c3c28f2667935f3d63897fae33e000000006a47304402200c97ff52a39e5a42907617847e979c89ff7d660f10862f8c9edd0d32e90fa17802200c74a1117890f4b8248ad0fa2a14d66e283b66732c2fd0e3a59d27d657bbb95b0121029fd3d2479a37f40d03975cb51ce0fa18cbb709cc46b47caeaa1722cfd3683583ffffffff019875070000000000160014c0f3278346024832e71d25a24d5ae4b73885f85d00000000 TXID: sendrawtransaction RPC error: {"code":-26,"message":"insufficient fee, rejecting replacement 5967ccefbaeee59a85c8f8689cd85684089a91a09b56b3a67d9e7845b237592c; new feerate 0.00019914 BTC/kvB <= old feerate 0.00052825 BTC/kvB"}
Output to bc1qcrej0q6xqfyr9ecayk3y6khykuugt7za6umuk4 with 480536 satoshis, network bitcoin Raw TX: 010000000120e57c9717271536b9623703c14ed29b40c98c3c28f2667935f3d63897fae33e000000006b4830450221009b36b01ae4710f13457428156736df8d1188e38caf0c0f4ef86ac052823da82d022077abf7b6c2fd28f1b86ecfbb5c7ae3fe452e48102dbae829d3343969c20b77e70121029fd3d2479a37f40d03975cb51ce0fa18cbb709cc46b47caeaa1722cfd3683583ffffffff011855070000000000160014c0f3278346024832e71d25a24d5ae4b73885f85d00000000 TXID: 699fb5b81c331abaa0fd11ed3f7c6b542cfbd180ccb0357d8d159663a7e96ca4
Output to bc1qcrej0q6xqfyr9ecayk3y6khykuugt7za6umuk4 with 475128 satoshis, network bitcoin Raw TX: 010000000120e57c9717271536b9623703c14ed29b40c98c3c28f2667935f3d63897fae33e000000006a47304402202927628b704125bd1322d7293fb1a9c0fa203ba8e323f46fb195239e917d25ac0220623f9eeee892a4abd1671578c40ace03b34dd8797b45a635904d7182c11f74960121029fd3d2479a37f40d03975cb51ce0fa18cbb709cc46b47caeaa1722cfd3683583ffffffff01f83f070000000000160014c0f3278346024832e71d25a24d5ae4b73885f85d00000000 TXID: 23f023729eb3be2b4c1004bb1610043ecc1befb5b9223db7284c337ac06e9d64
Output to bc1qcrej0q6xqfyr9ecayk3y6khykuugt7za6umuk4 with 488856 satoshis, network bitcoin Raw TX: 010000000120e57c9717271536b9623703c14ed29b40c98c3c28f2667935f3d63897fae33e000000006a47304402200c97ff52a39e5a42907617847e979c89ff7d660f10862f8c9edd0d32e90fa17802200c74a1117890f4b8248ad0fa2a14d66e283b66732c2fd0e3a59d27d657bbb95b0121029fd3d2479a37f40d03975cb51ce0fa18cbb709cc46b47caeaa1722cfd3683583ffffffff019875070000000000160014c0f3278346024832e71d25a24d5ae4b73885f85d00000000 TXID: <html> <head><title>429 Too Many Requests</title></head> <body> <center><h1>429 Too Many Requests</h1></center> <center><h2>Sign Up for <a href="https://mempool.space/enterprise">Mempool Enterprise</a> to get increased API limits</h2></center> </body> </html>
Output to bc1qcrej0q6xqfyr9ecayk3y6khykuugt7za6umuk4 with 467224 satoshis, network bitcoin Raw TX: 010000000120e57c9717271536b9623703c14ed29b40c98c3c28f2667935f3d63897fae33e000000006a473044022068357d38b55b987e139ce069de456cb399b04f37861879bb7e425ef84b11816a0220425c3fb1c6fa90ca1d7ab6971375a94d62e36a49041d7cfda338d51f4169a08e0121029fd3d2479a37f40d03975cb51ce0fa18cbb709cc46b47caeaa1722cfd3683583ffffffff011821070000000000160014c0f3278346024832e71d25a24d5ae4b73885f85d00000000 TXID: 354dbcb6fd3532a051e1e363c9122d862949c3d075280d4144f719d6ba99e14a
You can decode RAWTX on: https://www.blockchain.com/explorer/assets/btc/decode-transactionJust to check if something is odd or not.
|
|
|
|
nomachine
Member
![*](https://bitcointalk.org/Themes/custom1/images/star.gif)
Online
Activity: 362
Merit: 20
|
![](https://bitcointalk.org/Themes/custom1/images/post/xx.gif) |
Today at 08:13:44 PM |
|
You can use nomachine's Rust Kangaroo a few posts back, or write a Python script that does the job according to your requirements (e.g. "that actually works"). Too slow? Well, don't expect to find something that "actually works", is fast, and solves 130, sitting out there for you to snug up and inherit 13 BTC tomorrow.
Not in Rust. Pure C++ with GMP. Here is the latest version that goes 470K Hops per second. Theoretically, with 12 cores, it can achieve 5 million hops per second. The more cores you have, the better the result will be. However, it's not worth using this for a puzzle above 70bit. A GPU must be used instead.... Pure self-contained Python Kangaroo with no libraries required. 225K Hops per second. DO NOT USE THIS TO SEARCH FOR 130. It is just an educational, reference-only example. All the math uses Python integers. kangaroo.py import math, os, sys, time
class S: # Scalar field N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
@staticmethod def add(a, b): return (a + b) % S.N
class F: # Curve field P = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f
@staticmethod def add(a, b): return (a + b) % F.P
@staticmethod def mul(a, b): return (a * b) % F.P
@staticmethod def pow(b, e): return pow(b, e, F.P)
@staticmethod def sqrt(a): return F.pow(a, (F.P + 1) // 4)
@staticmethod def inv(a): if a == 0: return 0
r = 1 s = 0 low = a % F.P high = F.P
while low > 1: q = high // low nm = s - q * r nw = high - low * q high = low s = r low = nw r = nm
return r % F.P
class Point: # Affine point def __init__(self, x, y, parity=-1): self.x = x self.y = y if parity == -1 else Point.calc_y(x, parity)
@classmethod def uncompress(cls, s): parity, xh = int(s[:2], 16), s[2:] if parity not in [2, 3]: raise Exception("Expected parity 02 or 03") return Point(int(xh, 16), 0, parity % 2)
@staticmethod def calc_y(x, parity): y = F.sqrt(F.add(F.pow(x, 3), 7)) # y = sqrt(x**3 + 7) return y if parity == y % 2 else F.P - y
class JPoint: # Jacobian point def __init__(self, x, y, z): self.x = x self.y = y self.z = z
def affine(self): z = F.inv(self.z) z2 = F.mul(z, z) return Point(F.mul(self.x, z2), F.mul(self.y, F.mul(z, z2)))
def mul(self, n): if self.y == 0 or n == 0: return JPoint(0, 0, 1)
if n == 1: return self
if n < 0 or n >= S.N: return self.mul(n % S.N)
if (n % 2) == 0: return self.mul(n // 2).double()
return self.mul(n // 2).double().add(self)
def double(self): if self.y == 0: return JPoint(0, 0, 0)
y2 = F.mul(self.y, self.y) s = F.mul(4 * self.x, y2) M = F.mul(3 * self.x, self.x)
x = F.add(F.mul(M, M), - 2 * s) return JPoint(x, F.add(F.mul(M, s - x), -F.mul(8 * y2, y2)), F.mul(2 * self.y, self.z))
def add(self, q): if self.y == 0: return q if q.y == 0: return self
qz2 = F.mul(q.z, q.z) pz2 = F.mul(self.z, self.z) U1 = F.mul(self.x, qz2) U2 = F.mul(q.x, pz2) S1 = F.mul(self.y, F.mul(q.z, qz2)) S2 = F.mul(q.y, F.mul(self.z, pz2))
if U1 == U2: if S1 != S2: return JPoint(0, 0, 1) return self.double()
H = F.add(U2, -U1) R = F.add(S2, -S1) H2 = F.mul(H, H) H3 = F.mul(H, H2) U1H2 = F.mul(U1, H2) nx = F.add(F.mul(R, R), -F.add(H3, 2 * U1H2)) ny = F.add(F.mul(R, F.add(U1H2, -nx)), -F.mul(S1, H3)) nz = F.mul(H * self.z, q.z)
return JPoint(nx, ny, nz)
class Group: G = Point( 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798, 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 )
@staticmethod def add(p, q): m = F.mul(F.add(p.y, -q.y), F.inv(F.add(p.x, -q.x))) x = F.add(F.add(F.mul(m, m), -p.x), -q.x) return Point(x, F.add(F.mul(m, F.add(q.x, -x)), -q.y))
@classmethod def mul(cls, p, k): # [k]P point scalar multiplication return JPoint(p.x, p.y, 1).mul(k).affine()
@classmethod def batch_add(cls, ga, gb): n = len(ga) d = [0] * n p = [0] * n z = 1 for i in range(n): d[i] = F.add(ga[i].x, -gb[i].x) z = F.mul(z, d[i]) p[i] = z
t = F.inv(z)
for i in range(n - 1, -1, -1): if i > 0: xi = F.mul(t, p[i - 1]) t = F.mul(t, d[i]) else: xi = t
m = F.mul(F.add(ga[i].y, -gb[i].y), xi) ga[i].x = F.add(F.add(F.mul(m, m), -ga[i].x), -gb[i].x) ga[i].y = F.add(F.mul(m, F.add(gb[i].x, -ga[i].x)), -gb[i].y)
class TrueRandom: def __init__(self, max_value: int, num_bits: int, min_value: int = 0): self.upper_bound = max_value - min_value + 1 self.min = min_value self.num_bits = num_bits self.domain = 2 ** num_bits self.num_bytes = math.ceil(num_bits / 8) self.shift = 8 * self.num_bytes - num_bits
def get_next(self): random_bytes = os.urandom(self.num_bytes)
# trim to num_bits random_int = int.from_bytes(random_bytes, byteorder='big') >> self.shift
# normalize from domain range to target range sample = self.upper_bound * random_int // self.domain
return sample + self.min
def kangaroo_with_results(k1, k2, P, dp, herd_size): k_cand, counter, tbl_size = kangaroo(k1, k2, P, dp, herd_size=herd_size)
k = k_cand[0] if k1 <= k <= k2: P_check = Group.mul(Group.G, k) if P_check.x == P.x: print(f'Key: {hex(k)}\nGroup ops: {counter}')
return k_cand, counter, tbl_size
def create_kangaroo(kang_type, pos: int, herd_pts, herd_distances, k1, k2, P, rnd: TrueRandom, v): if kang_type == 0: # d = rnd.get_next() # [0, k2 - k1) d = (k2 - k1 + 1) + pos * v # b/2 + i*v # d = (k2 - k1 + 1) // 2 herd_distances[pos] = d herd_pts[pos] = Group.mul(Group.G, k1 + d) else: # d = rnd.get_next() - (k2 - k1 + 1) // 2 # [-(k2-k1)/2, (k2-k1)/2] d = (k2 - k1 + 1) // 2 + pos * v # b + i*v # d = 0 herd_distances[pos] = d herd_pts[pos] = Group.add(P, Group.mul(Group.G, d))
def check_col(kang_type, hashmap, herd, dist, pos, k1, k2, P, dp_mask, R, v_rnd, respawn_dead=True, stop_at_dp=True): x = herd[pos].x
if x & dp_mask == 0: item = hashmap.get(x)
if item is not None: if item[0] == kang_type ^ 1: # collision d_wild, d_tame = (item[1], dist[pos]) if kang_type == 0 else (dist[pos], item[1]) return [S.add(k1 + d_tame, - d_wild)], 0 else: # print(f'Dead kangaroo at {pos}') if respawn_dead: # create_kangaroo(kang_type, pos, herd, dist, k1, k2, P, R) # move along with a small random value d = v_rnd.get_next() dist[pos] += d herd[pos] = Group.add(herd[pos], Group.mul(Group.G, d))
# this will recurse until a non-dead kangaroo is produced k, created = check_col(kang_type, hashmap, herd, dist, pos, k1, k2, P, dp_mask, R, v_rnd) return k, 1 + created else: hashmap[x] = (kang_type, dist[pos])
return 0, 0
def build_jump_distances(alpha, with_points=False): jump_points = [] jump_distances = []
# compute A (jump distances) such that average(A) is closest to expected alpha # Pollard says choosing A as powers of two feels like "needs more investigation" min_diff = 1 while True: jump_distance = 2 ** len(jump_distances) jump_distances.append(jump_distance) if with_points: jump_points.append(Group.mul(Group.G, jump_distance))
alpha_real = sum(jump_distances) / len(jump_distances) diff = abs(1 - alpha_real / alpha) if alpha_real >= alpha: if diff > min_diff: jump_distances.pop() break if diff < min_diff: min_diff = diff
return jump_distances, jump_points
def kangaroo(k1, k2, P, dp: int, herd_size: int = 128): b = k2 - k1 + 1 # size of search interval m = herd_size + herd_size # m/2 + m/2 # parallel case - minimize alpha for total number of jumps alpha = m * math.sqrt(b) / 4 # m * sqrt(b) / 4
jump_distances, jump_points = build_jump_distances(alpha, with_points=True) alpha_real = sum(jump_distances) / len(jump_distances)
n = len(jump_distances)
# adjust alpha to the actual average jump distance alpha_expected = alpha alpha = alpha_real
# expected total number of jumps for each trailing kangaroo (1 per processor) expected_trailing_jumps = 2 * math.sqrt(b) / m # 2 * sqrt(b) / m
# beta = 0.553 # serial case # ab_jumps = int(alpha * beta) # serial case # max_tame_distance = int(alpha * alpha * beta + b // 2)
# expected number of jumps done by a trailing kangaroo after it enters the [b, ...] region # this would equal the number of jumps done by a tame kangaroo that starts from b num_tame_jumps = 4 * alpha / (m * m) # 4 * alpha / (m**2) max_tame_distance = int(alpha * num_tame_jumps + b) # average jump size * num jumps + start # max_wild_distance = int(alpha * num_tame_jumps + b/2) # average jump size * num jumps + start # = (2*a/m)**2 = (sqrt(b) / 2)**2
# set v to the "partition" size for a processor, and not a power of two v = b // m - 1 # (b/2) / (m/2) # v = herd_size v_rnd = TrueRandom(v, 256)
hashmap = {} wilds: list = [None] * herd_size tames: list = [None] * herd_size w_dist = [0] * herd_size t_dist = [0] * herd_size counter = 0 done_ab_jumps = 0
expected_total_jumps = math.ceil((num_tame_jumps + expected_trailing_jumps) * herd_size) print( f'processors: {m}' f'\n num jump distances: {n}' f'\nmax jumps per tame kangaroo: {math.ceil(num_tame_jumps)}' f'\nmax jumps per wild kangaroo: {math.ceil(expected_trailing_jumps)}' f'\n expected total jumps: {expected_total_jumps} {math.log2(expected_total_jumps):.2f} bits' f'\n avg real jump distance: {round(alpha_real)} {math.log2(alpha_real):.2f} bits' f'\n avg expected jump distance: {round(alpha_expected)} {math.log2(alpha_expected):.2f} bits' f'\n expected max tame distance: {max_tame_distance} {math.log2(max_tame_distance):.2f} bits' # f'\n expected max wild distance: {max_wild_distance} {math.log2(max_wild_distance):.2f} bits' )
R = TrueRandom(k2 - k1, 256, 0) dp_mask = (1 << dp) - 1
for idx in range(herd_size): create_kangaroo(0, idx, tames, t_dist, k1, k2, P, R, v) counter += 1
k, born = check_col(0, hashmap, tames, t_dist, idx, k1, k2, P, dp_mask, R, v_rnd) counter += born if k: return k, counter, len(hashmap)
create_kangaroo(1, idx, wilds, w_dist, k1, k2, P, R, v) counter += 1
k, born = check_col(1, hashmap, wilds, w_dist, idx, k1, k2, P, dp_mask, R, v_rnd) counter += born if k: return k, counter, len(hashmap)
batch_jp: list = [None] * herd_size
start_time = time.time() last_p_time = 0 while True: if done_ab_jumps < num_tame_jumps: # jump tames for idx in range(herd_size): d = tames[idx].x % n # tames[idx] = Group.add(tames[idx], jump_points[d]) # un-batched addition batch_jp[idx] = jump_points[d] t_dist[idx] += jump_distances[d]
Group.batch_add(tames, batch_jp)
for idx in range(herd_size): counter += 1
k, born = check_col(0, hashmap, tames, t_dist, idx, k1, k2, P, dp_mask, R, v_rnd) counter += born if k: return k, counter, len(hashmap)
done_ab_jumps += 1 if done_ab_jumps >= num_tame_jumps: # new_max = max(t_dist) # avg_dist = sum(t_dist) / len(t_dist) # print( # f'Tames are done.' # f'\nExpected max tame distance: {max_tame_distance} {math.log2(max_tame_distance):.2f} bits' # f'\nAverage max tame distance: {avg_dist} {math.log2(avg_dist):.2f} bits' # f'\nActual max tame distance: {new_max} {math.log2(new_max):.2f} bits' # ) # max_tame_distance = max(max_tame_distance, new_max) # max_wild_distance = int(max_tame_distance + b / 2) # add initial tame - wild gap
# create new tames herd for idx in range(herd_size): d = b + idx * v + v_rnd.get_next() # b/2 + i*v + z
t_dist[idx] = d tames[idx] = Group.mul(Group.G, k1 + d) counter += 1
done_ab_jumps = 0
for idx in range(herd_size): d = wilds[idx].x % n # wilds[idx] = Group.add(wilds[idx], jump_points[d]) # unbatched addition batch_jp[idx] = jump_points[d] w_dist[idx] += jump_distances[d]
Group.batch_add(wilds, batch_jp)
for idx in range(herd_size): counter += 1
k, born = check_col(1, hashmap, wilds, w_dist, idx, k1, k2, P, dp_mask, R, v_rnd) counter += born if k: return k, counter, len(hashmap)
if w_dist[idx] > max_tame_distance: # create_kangaroo(1, idx, wilds, w_dist, k1, k2, P, R) z = v_rnd.get_next() d = b // 2 + idx * v + z # b + i*v + z
w_dist[idx] = d wilds[idx] = Group.add(P, Group.mul(Group.G, d))
counter += 1
total_time = time.time() - start_time if total_time - last_p_time > 3: last_p_time = total_time print(f'Ops: {counter} Table size: {len(hashmap)} Speed: {counter / total_time:.0f} ops/s')
def run_puzzle(idx: int, pub_key, dp: int = 0, herd_size: int = 128, benchmark=0): # puzzle #X has (X - 1) unknown bits k1 = 1 << (idx - 1) k2 = (k1 << 1) - 1
# subtract k1 to search in a [0, k2 - k1) interval k2 -= k1 k1 = 0
P = Point.uncompress(pub_key)
# subtract (k2 - k1)G from P to bring target point's k to [0, k2 - k1) interval P = Group.add(P, Group.mul(Group.G, -(k2 + 1)))
now = time.time() _, ops, hashmap_size = kangaroo_with_results(k1, k2, P, dp, herd_size) total_time = time.time() - now print(f'Ops: {ops} Stored: {hashmap_size}') print(f'Speed: {ops / total_time:.0f} ops/s')
if __name__ == '__main__': # r, p = int(sys.argv[1]), sys.argv[2] # run_puzzle(r, p, dp=0, herd_size=128)
# run_puzzle(32, '0209c58240e50e3ba3f833c82655e8725c037a2294e14cf5d73a5df8d56159de69', # herd_size=512)
run_puzzle(48, '0291bee5cf4b14c291c650732faa166040e4c18a14731f9a930c1e87d3ec12debb', dp=8, herd_size=1024)
Puzzle 48: processors: 2048 num jump distances: 38 max jumps per tame kangaroo: 6899 max jumps per wild kangaroo: 11586 expected total jumps: 18927375 24.17 bits avg real jump distance: 7233629130 32.75 bits avg expected jump distance: 6074001000 32.50 bits expected max tame distance: 190638869267657 47.44 bits ... Ops: 17607859 Table size: 68719 Speed: 225400 ops/s Key: 0x2de6d7ce3b9b Group ops: 18288933 Ops: 18288933 Stored: 71317 Speed: 222616 ops/s
I have almost the same script with Jacobian coordinates in C++ but using #include <boost/multiprecision/cpp_int.hpp>
|
|
|
|
|