jovica888 (OP)
Jr. Member
Offline
Activity: 57
Merit: 17
|
 |
January 27, 2025, 10:56:02 PM Merited by NotATether (5) |
|
So I am learning about everything and so there is a chance that this post can be lame/noob or something like that I created a smaller secp256k1, p=43 n=31 I took point G(2, 31) for the generator point and I got the list of all valid points G=(2,31) 2G=(7,36) 3G=(35,22) 4G=(21,25) 5G=(12,31) 6G=(29,12) 7G=(25,25) 8G=(32,3) 9G=(20,3) 10G=(42,36) 11G=(40,18) 12G=(37,7) 13G=(13,22) 14G=(34,3) 15G=(38,22) 16G=(38,21) 17G=(34,40) 18G=(13,21) 19G=(37,36) 20G=(40,25) 21G=(42,7) 22G=(20,40) 23G=(32,40) 24G=(25,18) 25G=(29,31) 26G=(12,12) 27G=(21,18) 28G=(35,21) 29G=(7,7) 30G=(2,12) I printed this and I put it on my wall so when I work (I work from home) sometimes I look into this paper and I tried to find something interesting (interesting for me  ) so this is what I found and also those rules can be applied on regular secp256k1 that Bitcoin is using... Every Y has 3 different X values... When you calculate G of those points you always get n=31 so G=(2,31) + 5G=(12,31) + 25G=(29,31) = 31G, also for all other points 2G=(7,36) + 10G=(42,36) + 19G=(37,36) = 31G If you change generator points those positions will remain the same so for n=31 you will always get the same Y on the same sets of points 1 5 25, 2 10 19... there are 10 sets of this points There are negative points set with 1 5 25 and 6 26 30 (6 26 30 starting from the "end" to start" basically) When you do positive set + negative set of points those point will always return 93G or 3n I found that if you do for one set of point X1 + X2 +X3 you sometimes get 2P and sometimes get only P I do not know why... so on original curve where y is 483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 you have 3 X first x: c994b69768832bcbff5e9ab39ae8d1d3763bbf1e531bed98fe51de5ee84f50fb second x: 79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 third x: bcace2e99da01887ab0102b696902325872844067f15e98da7bba04400b88fcb If you do X1 + X2 + X3 in this case you will get 2P in some other cases I found that I only get 1P Y 4218f20ae6c646b363db68605822fb14264ca8d2587fdd6fbc750d587e76a7ee first x: 1 second x: 7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee third x: 851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40 In this case you get only P when you do X1 + X2 + X3 I found that for symmetrical points if you do Y1+Y2 you always get P b7c52588d95c3b9aa25b0403f1eef75702e84bb7597aabe663b82f6f04ef2777 + 79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 = p . . . Is there and useful way that we can use those points if we can calculate their G positions? I am testing bigger and bigger curves and always looking for n that number of points mod 6 = 0 (+ infinity point) p = 937 n = 973 1G 235G 737G So I am trying to make a connection between 1st and 2nd point for any p and any n.... If I know 1st and 2nd point I can easily calculate 3rd = n - 1st - 2nd then I can calculate the position of other 3 points that has different Y but same 3 X If we know the relations between those points maybe we can scan keys faster or see some periodical groups I do not know
|
|
|
|
iceland2k14
Member

Offline
Activity: 70
Merit: 86
|
 |
January 28, 2025, 11:19:07 AM |
|
secp256k1 curve is With the help of cuberoot of Unity, we can say that each value of Y there will be 3 values of X. (Endomorphism Points) In a similar way For each X there will be 2 values of Y. (symmetry Points) The relationships between them are well known and already used in various tools for faster scanning (example VanitySearch from JLP). In a very simple way if you have a Pubkey points (x, y) you can get in total 6 pubkeys easily through 6 Pubkeys = [x,y] [x*beta%p, y] [x*beta2%p, y] [x,p-y] [x*beta%p, p-y] [x*beta2%p, p-y] These points are related with the Generator through Privatekeys like this 6 Pvkeys = pvk, pvk*lmda%N, pvk*lmda2%N, N-pvk, N-pvk*lmda%N, N-pvk*lmda2%N Here the secp256k1 constants are p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 # Constants Based on Cube root of 1 beta = 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee beta2 = 0x851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40 # beta*beta lmda = 0x5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72 lmda2 = 0xac9c52b33fa3cf1f5ad9e3fd77ed9ba4a880b9fc8ec739c2e0cfc810b51283ce # lmda*lmda
|
|
|
|
dexizer7799
Newbie
Offline
Activity: 42
Merit: 0
|
 |
January 31, 2025, 09:26:29 AM |
|
|
|
|
|
jovica888 (OP)
Jr. Member
Offline
Activity: 57
Merit: 17
|
 |
February 04, 2025, 07:55:42 PM |
|
@dexizer7799 Thank you but I think this is an example for different type of curve... I do not know I did not understand the content of that link
for small secp256k1 I found that if you do addition of all X values for all points and do mod p you get 0
So if P=97 I get n=79
if I do the addition of all valid points Gx+2Gx+3Gx+4Gx....+78Gx Where Generator point is P (1,69) then I get 3880 mod 97 = 0
Maybe this can be usefull
|
|
|
|
stwenhao
|
 |
February 04, 2025, 09:58:47 PM |
|
The smallest valid example I can come up with: Curve p=7, n=13, y^2=x^3+3, generator=(1,2) Server to execute code: https://sagecell.sagemath.org/p=7 n=13 K=GF(p) a=K(0) b=K(3) E=EllipticCurve(K,(a,b)) G=E(1,2) E.set_order(n) d=1 P=d*G while d<n: print(d,P[0],P[1]) d+=1 P=d*G Table of private and public keys: +----+---+---+ | d | x | y | +----+---+---+ | 1 | 1 | 2 | | 2 | 6 | 3 | | 3 | 2 | 2 | | 4 | 4 | 5 | | 5 | 3 | 3 | | 6 | 5 | 3 | | 7 | 5 | 4 | | 8 | 3 | 4 | | 9 | 4 | 2 | | 10 | 2 | 5 | | 11 | 6 | 4 | | 12 | 1 | 5 | +----+---+---+ And then, everything can be rotated just like in a clock, with additional 13th point at infinity. Later, you can try to go into bigger and bigger curves, and get for example everything below 100: p=5 while p<100: n_values=[] b_value=1 while len(n_values)<6: K=GF(p) a=K(0) b=K(b_value) E=EllipticCurve(K,(a,b)) n=E.order() if n == p+1: n_values.append(n) n_values.append(n) n_values.append(n) n_values.append(n) n_values.append(n) n_values.append(n) else: if n not in n_values: n_values.append(n) b_value+=1 if n_values[0] != p+1: print(p,n_values) p=next_prime(p) It is just slightly modified example from vjudeu's code: https://github.com/vjudeu/curves1000/wiki/Six-n%E2%80%90values-when-changing-b%E2%80%90valueAs you can probably see, you can get these results: 7 [12, 9, 13, 3, 7, 4] 13 [12, 19, 9, 21, 16, 7] 19 [12, 13, 21, 27, 28, 19] 31 [36, 43, 39, 21, 25, 28] 37 [48, 49, 39, 37, 28, 27] 43 [36, 52, 49, 39, 31, 57] 61 [48, 61, 75, 63, 76, 49] 67 [84, 73, 52, 57, 63, 79] 73 [84, 81, 57, 91, 64, 67] 79 [84, 63, 97, 93, 67, 76] 97 [84, 117, 93, 79, 103, 112] Another similar topic, which may be useful: https://bitcointalk.org/index.php?topic=5459153.0Here, Garlo Nicon was trying just y^2=x^3+7, and checked only values, where p-value and n-value can be swapped, but as it is not the case in secp192k1 and secp224k1, and works only for secp160k1 and secp256k1, then probably other b-values should be considered as well.
|
|
|
|
OfficialGratejoy
Newbie
Offline
Activity: 28
Merit: 2
|
 |
February 05, 2025, 04:06:58 PM |
|
The smallest valid example I can come up with: Curve p=7, n=13, y^2=x^3+3, generator=(1,2) Server to execute code: https://sagecell.sagemath.org/p=7 n=13 K=GF(p) a=K(0) b=K(3) E=EllipticCurve(K,(a,b)) G=E(1,2) E.set_order(n) d=1 P=d*G while d<n: print(d,P[0],P[1]) d+=1 P=d*G Table of private and public keys: +----+---+---+ | d | x | y | +----+---+---+ | 1 | 1 | 2 | | 2 | 6 | 3 | | 3 | 2 | 2 | | 4 | 4 | 5 | | 5 | 3 | 3 | | 6 | 5 | 3 | | 7 | 5 | 4 | | 8 | 3 | 4 | | 9 | 4 | 2 | | 10 | 2 | 5 | | 11 | 6 | 4 | | 12 | 1 | 5 | +----+---+---+ And then, everything can be rotated just like in a clock, with additional 13th point at infinity. Later, you can try to go into bigger and bigger curves, and get for example everything below 100: p=5 while p<100: n_values=[] b_value=1 while len(n_values)<6: K=GF(p) a=K(0) b=K(b_value) E=EllipticCurve(K,(a,b)) n=E.order() if n == p+1: n_values.append(n) n_values.append(n) n_values.append(n) n_values.append(n) n_values.append(n) n_values.append(n) else: if n not in n_values: n_values.append(n) b_value+=1 if n_values[0] != p+1: print(p,n_values) p=next_prime(p) It is just slightly modified example from vjudeu's code: https://github.com/vjudeu/curves1000/wiki/Six-n%E2%80%90values-when-changing-b%E2%80%90valueAs you can probably see, you can get these results: 7 [12, 9, 13, 3, 7, 4] 13 [12, 19, 9, 21, 16, 7] 19 [12, 13, 21, 27, 28, 19] 31 [36, 43, 39, 21, 25, 28] 37 [48, 49, 39, 37, 28, 27] 43 [36, 52, 49, 39, 31, 57] 61 [48, 61, 75, 63, 76, 49] 67 [84, 73, 52, 57, 63, 79] 73 [84, 81, 57, 91, 64, 67] 79 [84, 63, 97, 93, 67, 76] 97 [84, 117, 93, 79, 103, 112] Another similar topic, which may be useful: https://bitcointalk.org/index.php?topic=5459153.0Here, Garlo Nicon was trying just y^2=x^3+7, and checked only values, where p-value and n-value can be swapped, but as it is not the case in secp192k1 and secp224k1, and works only for secp160k1 and secp256k1, then probably other b-values should be considered as well. The secp256k1 you created for testing how did it go?
|
|
|
|
jovica888 (OP)
Jr. Member
Offline
Activity: 57
Merit: 17
|
 |
February 20, 2025, 01:32:45 PM Last edit: May 09, 2025, 07:46:20 AM by mprep |
|
I do not want to create a new thread I just want to continue here... I tried to figure out how BSGS works for scanning points and how it maybe can be improved... Many BSGS scanners makes babystep file where you take starting point and the add +G+G+G+G+G+G to get for example 300.000.000 consecutive points Then scanner will jump 300M per iteration and check if the current point is on the list... But I think that there is no need for all points to be consecutive. You can spread them all over the range just make sure that when you generating the babystep file have the rule where iteration * 300.000.000 * (some fixed number) + Iteration.... For example For every point in theory if you do mod 300.000.000 of distance between start point and any generated point you will get all posible remainings for 300.000.000... so that means when you scan you can still jump regular jumps even if there is huge gap between points and you will find a solution sooner because points are not at the same place I think this can be improved more.... -------------------------------------------------------- Also, for example, in puzzle 135 we have our goal point X: 145D2611C823A396EF6712CE0F712F09B9B4F3135E3E0AA3230FB9B6D08D1E16 Y: 667A05E9A1BDD6F70142B66558BD12CE2C0F9CBC7001B20C8A6A109C80DC5330 From this point we can do subtraction 0x4000000000000000000000000000000000 * G we will get some point and then we take simetrical point - the point in upper region Then we make a list (babystep file) of all X values from 1G to 300.000.000G So we can start scanning from a symmetrical point and we go UP... but then we can jump 600.000.000 keys per jump so we can double the speed - when we hit some X value we have 2 solutions and one of them is correct
I am not sure about the method where we put gaps between points in the babystep file because there is infinity point so after infinity point all points are moved by 1 so if you jump 600.000.000 keys per jump and you have only 300.000.000 points in BS file I am not sure that it will find a solution because other half of points are moved by 1 In regular BSGS that must work - it does not work only in case if you hit the infinity point when you jump for 600.000.000 keys... But I think the chances for that are small I have only this code for generating lines When I generate 300.000.000 keys I take only first 16 characters for matching. It is a simple code and can be improved on many ways. I am not so good at python I was working with PHP like 15 years import secp256k1 as ice import os
# Starting point P = ice.pub2upub('02145d2611c823a396ef6712ce0f712f09b9b4f3135e3e0aa3230fb9b6d08d1e16')
batch_size = 30_000_000 max_lines = 300_000_000 babystep_file = "babystep.txt"
if os.path.exists(babystep_file): with open(babystep_file, "r") as f: line_count = sum(1 for _ in f) else: line_count = 0
with open(babystep_file, "a") as f: while line_count < max_lines: print(f"Generating {batch_size} BSGS points...") bsgs_batch = ice.point_sequential_increment(batch_size, P) for i in range(batch_size): hex_string = bsgs_batch[i * 65: i * 65 + 65].hex() x_hex = hex_string[2:18] f.write(f"{x_hex}\n") line_count += 1 if line_count >= max_lines: break P = ice.pub2upub(bsgs_batch[-65:].hex()) print(f"Current generating: {line_count}/{max_lines} lines.")
print("Generating of 300.000.000 lines completed.")
my idea is to create ONE babystep file and count that file twice because you can double the number of consecutive X values because they are going in one direction then in the reverse direction (with 0 point in the middle) Our goal point 02145d2611c823a396ef6712ce0f712f09b9b4f3135e3e0aa3230fb9b6d08d1e16 I have this code for subtraction of points so I used it import secp256k1 as ice
def ECsubtract(Q1,Q2):# compressed or uncompressed pubkey Q1=ice.pub2upub(Q1) Q2=ice.pub2upub(Q2) sub=ice.point_negation(Q2)# -Q2 return (ice.point_addition(Q1,sub).hex()) #Q1 - Q2
public_key=ECsubtract('02145d2611c823a396ef6712ce0f712f09b9b4f3135e3e0aa3230fb9b6d08d1e16','02cbb434aa7ae1700dcd15b20b17464817ec11715050e0fa192ffe9c29a673059f') print(public_key) 02cbb434aa7ae1700dcd15b20b17464817ec11715050e0fa192ffe9c29a673059f = 4000000000000000000000000000000000 * G I got this point 04a8c204d9e0cd0e7f6da825d55b5c2b9d0093f96650bf37e67bc802189b3bc47837bbe3fd17f83a190242af1da9673c468f504b37ba276554a9724ea479124d87 Upper region point is 04a8c204d9e0cd0e7f6da825d55b5c2b9d0093f96650bf37e67bc802189b3bc478c8441c02e807c5e6fdbd50e25698c3b970afb4c845d89aab568db15a86edaea8 From this point we can start. Make babystep file from 1G to XG (how much RAM do you have) and then start scanning...
You are creating Babystep file from 1G to 10G in babystep file you only put X values (or part of it or I do not know) You are jumping from 264G ----> inverse point n - 264 And you can jump 20G in one jump and try to match X values of the point... number of line you hit is for example 3... you have 2 solutions ... private key = n - nuber of jumps * 20 - 3 private key = n - nuber of jumps * 20 - 3 * 2 - 1(because of infinity point) I mean this is something I am thinking about not sure
I also have another Idea like a Kangaroo that will use the infinity point as a referent point so the kangaroo will jump from the public key up and we will save X values of those points when the code jumps over the infinity point then the kangaroo will basically start jumping back because X values now have order in backward... and then when you find collision with itself you can calculate the private key priv_key = (n - (G_added - G_at_collision) // 2 - G_at_collision) % n So in my code I was looking for private key of 03440daba3905488f1b5ad2186f6ce2e9a9fe69327ac975dba1a93f8ed60d7813d I know that private key is < n/2 so I took the even Y value to have a point > n/2 here is the code import ecdsa from ecdsa.ellipticcurve import Point import time
# Parameters of the secp256k1 elliptic curve curve = ecdsa.curves.SECP256k1.curve G = ecdsa.curves.SECP256k1.generator n = ecdsa.curves.SECP256k1.order
# Initial point X = 0x440daba3905488f1b5ad2186f6ce2e9a9fe69327ac975dba1a93f8ed60d7813d Y = 0x9d656a2ee1049d7bf9c4b48c4df47e92115b0a479c60ba1034c9c2e7a39d2f0c
P = Point(curve, X, Y)
visited_x = {} # Store X coordinates in RAM G_added = 0 # Total G added start_time = time.time() # Start time last_print_time = start_time # Track last print time iteration = 0 # Track current iteration
while True: last5 = X & 0xFFFFF # Last 5 digits of X-axis step = last5 + 1 # Step size P = P + step * G # Jump forward X = P.x() G_added += step iteration += 1 current_time = time.time() if current_time - last_print_time >= 5: print(f"Total G added: {hex(G_added)}, Current Iteration: {iteration}, Current step: {step}", end="\r") last_print_time = current_time if X in visited_x: G_at_collision = visited_x[X] priv_key = (n - (G_added - G_at_collision) // 2 - G_at_collision) % n end_time = time.time() elapsed_time = end_time - start_time hours, rem = divmod(elapsed_time, 3600) minutes, seconds = divmod(rem, 60) print(f"\nPrivate key found: {hex(priv_key)}") print(f"Time taken: {int(hours)}h {int(minutes)}m {int(seconds)}s") break else: visited_x[X] = G_added
I know that the code is slow but it finds a solution Total G added: 0x11a4b3bb783, Current Iteration: 2312884, Current step: 699786 Private key found: 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25d8a18d30c97 Time taken: 0h 3m 19s So original private key is n - fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25d8a18d30c97 hex 102B76334AA dec 1111178294442 [moderator's note: consecutive posts merged]
|
|
|
|
NotATether
Legendary
Offline
Activity: 2100
Merit: 8931
Search? Try talksearch.io
|
 |
February 22, 2025, 06:26:19 AM |
|
That is very interesting. How did you know that G = (2, 31) would produce a curve that models secp256k1's properties, if I may ask? Is there any theorem in say group theory that describes this kind of construction?
I'm particularly interested in if there's the process with which cryptographers use to select prime numbers for a curve can be expressed as an algorithm.
|
|
|
|
jovica888 (OP)
Jr. Member
Offline
Activity: 57
Merit: 17
|
 |
February 22, 2025, 11:50:49 AM Last edit: February 22, 2025, 12:15:50 PM by jovica888 Merited by vapourminer (1) |
|
I was using this website https://asecuritysite.com/ecc/ecc_points_multI was putting random p-prime numbers, then "manually"  bruteforce X value to get valid point Then if you get rule (n-1)mod 6 = 0 then you basically got the smaller version of standard secp256k1 - you will get the sets of 2 Y values with 3 X values just like in regular curve The smallest example is p = 7 G=(1, 1) P (1,1) Point is on curve 2P (2,1) Point is on curve 3P (4,6) Point is on curve 4P (4,1) Point is on curve 5P (2,6) Point is on curve 6P (1,6) Point is on curve 7P=0
|
|
|
|
JackMazzoni
Jr. Member
Offline
Activity: 158
Merit: 6
|
 |
March 13, 2025, 10:15:06 AM |
|
I learn many things from this smaller secp256k1.
Uncompressed public key: 042f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4d8ac222636e5e 3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6
Three x values: x1 = 21505829891763648114329055987619236494102133314575206970830385799158076338148 x2 = 23285849548026170226712523888619559634478006467037872208296602441247713932904 x3 = 71000409797526377082529405132449111724689844884027484860330595767503044400611
Two y values: y1 = 98003708678762621233683240503080860129026887322874138805529884920309963580118 y2 = 17788380558553574189887744505607047724243097342766425233927699087598871091545 Enter private key for (x1, y1) = (21505829891763648114329055987619236494102133314575206970830385799158076338148, 98003708678762621233683240503080860129026887322874138805529884920309963580118): 5
Six public keys with private keys: Public key 1: 042f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4d8ac222636e5e 3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6 [Private key: 5] Validated: k1 matches Public key 2: 04337b52e3acda49dff79f54fbccb94671a045693ee0d097cc138c694695a83668d8ac222636e5e 3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6 [Private key: 72798312578463789091060122408687194401800723498338030560477939572921828405753] Validated: k2 matches Public key 3: 049cf8cecf391e958cb2ac03df28ea6865772f120342cdcd7c20cac14eb816d5e3d8ac222636e5e 3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6 [Private key: 42993776658852406332510862600000713451036840780736873822127223568596333088579] Validated: k3 matches Public key 4: 042f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe42753ddd9c91a1 c292b24562259363bd90877d8e454f297bf235782c459539959 [Private key: 115792089237316195423570985008687907852837564279074904382605163141518161494332] Validated: k4 matches Public key 5: 04337b52e3acda49dff79f54fbccb94671a045693ee0d097cc138c694695a836682753ddd9c91a1 c292b24562259363bd90877d8e454f297bf235782c459539959 [Private key: 42993776658852406332510862600000713451036840780736873822127223568596333088584] Validated: k5 matches Public key 6: 049cf8cecf391e958cb2ac03df28ea6865772f120342cdcd7c20cac14eb816d5e32753ddd9c91a1 c292b24562259363bd90877d8e454f297bf235782c459539959 [Private key: 72798312578463789091060122408687194401800723498338030560477939572921828405758] Validated: k6 matches
Sum of private keys for y1 = 115792089237316195423570985008687907852837564279074904382605163141518161494337 (should be n or 2n) Sum of private keys for y2 = 231584178474632390847141970017375815705675128558149808765210326283036322988674 (should be n or 2n)
|
Need Wallet Recovery? PM ME. 100% SAFE
|
|
|
LeTH3knXoDArzm
Newbie
Offline
Activity: 11
Merit: 10
|
 |
March 13, 2025, 10:50:11 AM Last edit: March 13, 2025, 11:34:03 AM by LeTH3knXoDArzm Merited by JackMazzoni (1) |
|
I learn many things from this smaller secp256k1.
Uncompressed public key: 042f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4d8ac222636e5e 3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6
Three x values: x1 = 21505829891763648114329055987619236494102133314575206970830385799158076338148 x2 = 23285849548026170226712523888619559634478006467037872208296602441247713932904 x3 = 71000409797526377082529405132449111724689844884027484860330595767503044400611
Two y values: y1 = 98003708678762621233683240503080860129026887322874138805529884920309963580118 y2 = 17788380558553574189887744505607047724243097342766425233927699087598871091545 Enter private key for (x1, y1) = (21505829891763648114329055987619236494102133314575206970830385799158076338148, 98003708678762621233683240503080860129026887322874138805529884920309963580118): 5
Six public keys with private keys: Public key 1: 042f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4d8ac222636e5e 3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6 [Private key: 5] Validated: k1 matches Public key 2: 04337b52e3acda49dff79f54fbccb94671a045693ee0d097cc138c694695a83668d8ac222636e5e 3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6 [Private key: 72798312578463789091060122408687194401800723498338030560477939572921828405753] Validated: k2 matches Public key 3: 049cf8cecf391e958cb2ac03df28ea6865772f120342cdcd7c20cac14eb816d5e3d8ac222636e5e 3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6 [Private key: 42993776658852406332510862600000713451036840780736873822127223568596333088579] Validated: k3 matches Public key 4: 042f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe42753ddd9c91a1 c292b24562259363bd90877d8e454f297bf235782c459539959 [Private key: 115792089237316195423570985008687907852837564279074904382605163141518161494332] Validated: k4 matches Public key 5: 04337b52e3acda49dff79f54fbccb94671a045693ee0d097cc138c694695a836682753ddd9c91a1 c292b24562259363bd90877d8e454f297bf235782c459539959 [Private key: 42993776658852406332510862600000713451036840780736873822127223568596333088584] Validated: k5 matches Public key 6: 049cf8cecf391e958cb2ac03df28ea6865772f120342cdcd7c20cac14eb816d5e32753ddd9c91a1 c292b24562259363bd90877d8e454f297bf235782c459539959 [Private key: 72798312578463789091060122408687194401800723498338030560477939572921828405758] Validated: k6 matches
Sum of private keys for y1 = 115792089237316195423570985008687907852837564279074904382605163141518161494337 (should be n or 2n) Sum of private keys for y2 = 231584178474632390847141970017375815705675128558149808765210326283036322988674 (should be n or 2n)
Endomorphism! public key 2 = beta * P.x || lambda * P (mod p) public key 3 = beta2 * P.x public key 4 = p - P.y() == inverse of p * G (mod p) public key 5 = x*beta%p, p-y == N-pvk*lmda%N public key 6 = x*beta2%p, p-y == N-pvk*lmda2%N python script that compute all of them in one shot (if helpful to anyone): from ecdsa.ellipticcurve import Point from ecdsa.curves import SECP256k1
# secp256k1 parameters curve = SECP256k1.curve p = curve.p() G = SECP256k1.generator
# Compute β = 2^((p-1)/3) mod p beta = pow(2, (p - 1) // 3, p) beta2 = 60197513588986302554485582024885075108884032450952339817679072026166228089408 lmbda = 37718080363155996902926221483475020450927657555482586988616620542887997980018 lmbda2 = 78074008874160198520644763525212887401909906723592317393988542598630163514319
# print(p) def parse_pubkey(pubkey: str): """Extracts x, y coordinates from an uncompressed '04' format public key.""" if not pubkey.startswith('04') or len(pubkey) != 130: raise ValueError("Invalid uncompressed public key format") x = int(pubkey[2:66], 16) y = int(pubkey[66:], 16) return Point(SECP256k1.curve, x, y, SECP256k1.order)
# beta * P.x == lambda * P (mod p) def endomorphism(P: Point) -> Point: x_new = (beta * P.x()) % p return Point(curve, x_new, P.y()) # p - P.y() == inverse of p * G (mod p) (negation of y) def endomorphism2(P: Point) -> Point: # x_new = ( P.x() * beta2) % p y_new = ( p - P.y() ) % p return Point(curve, P.x(), y_new)
def endomorphism3(P: Point) -> Point: x_new = (beta2 * P.x()) % p return Point(curve, x_new, P.y()) def endomorphism4(P: Point) -> Point: x_new = (beta * P.x()) % p y_new = (p - P.y()) % p return Point(curve, x_new, y_new) def endomorphism5(P: Point) -> Point: x_new = (beta2 * P.x()) % p y_new = (p - P.y()) % p return Point(curve, x_new, y_new)
pubkey = "042f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4d8ac222636e5e3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6" # compute given public key or P integer, decomment one or another. P = 6 * G # P = parse_pubkey(pubkey)
P_endomorph = endomorphism(P) P_endomorph2 = endomorphism2(P) P_endomorph3 = endomorphism3(P) P_endomorph4 = endomorphism4(P) P_endomorph5 = endomorphism5(P)
print("Original P :", (P.x(), P.y())) print(f"Originak P key 04{P.x():x}{P.y():x}") print('---------------------------------') print("Endomorph P [beta * P.x == lambda * P (mod p)]:", (P_endomorph.x(), P_endomorph.y())) print(f"Endomorph φ(P) key 04{P_endomorph.x():064x}{P_endomorph.y():064x}") print('---------------------------------') print("Endomorph2 P [p - P.y() == inverse of p * G (mod p) (negation of y)]:", (P_endomorph2.x(), P_endomorph2.y())) print(f"Endomorph2 φ(P) key 04{P_endomorph2.x():x}{P_endomorph2.y():x}") print('---------------------------------') print("Endomorph3 P [beta2 * P.x == 2nd beta iteration]:", (P_endomorph3.x(), P_endomorph3.y())) print(f"Endomorph3 φ(P) key 04{P_endomorph3.x():x}{P_endomorph3.y():x}") print('---------------------------------') print("Endomorph4 P [x*beta%p, p-y == N-pvk*lmda%N]:", (P_endomorph4.x(), P_endomorph4.y())) print(f"Endomorph4 φ(P) key 04{P_endomorph4.x():x}{P_endomorph4.y():x}") print('---------------------------------') print("Endomorph5 P [x*beta2%p, p-y == N-pvk*lmda2%N]:", (P_endomorph5.x(), P_endomorph5.y())) print(f"Endomorph5 φ(P) key 04{P_endomorph5.x():x}{P_endomorph5.y():x}")
|
|
|
|
mjojo
Newbie
Offline
Activity: 77
Merit: 0
|
 |
March 15, 2025, 05:52:31 AM |
|
I learn many things from this smaller secp256k1.
Uncompressed public key: 042f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4d8ac222636e5e 3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6
Three x values: x1 = 21505829891763648114329055987619236494102133314575206970830385799158076338148 x2 = 23285849548026170226712523888619559634478006467037872208296602441247713932904 x3 = 71000409797526377082529405132449111724689844884027484860330595767503044400611
Two y values: y1 = 98003708678762621233683240503080860129026887322874138805529884920309963580118 y2 = 17788380558553574189887744505607047724243097342766425233927699087598871091545 Enter private key for (x1, y1) = (21505829891763648114329055987619236494102133314575206970830385799158076338148, 98003708678762621233683240503080860129026887322874138805529884920309963580118): 5
Six public keys with private keys: Public key 1: 042f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe4d8ac222636e5e 3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6 [Private key: 5] Validated: k1 matches Public key 2: 04337b52e3acda49dff79f54fbccb94671a045693ee0d097cc138c694695a83668d8ac222636e5e 3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6 [Private key: 72798312578463789091060122408687194401800723498338030560477939572921828405753] Validated: k2 matches Public key 3: 049cf8cecf391e958cb2ac03df28ea6865772f120342cdcd7c20cac14eb816d5e3d8ac222636e5e 3d6d4dba9dda6c9c426f788271bab0d6840dca87d3aa6ac62d6 [Private key: 42993776658852406332510862600000713451036840780736873822127223568596333088579] Validated: k3 matches Public key 4: 042f8bde4d1a07209355b4a7250a5c5128e88b84bddc619ab7cba8d569b240efe42753ddd9c91a1 c292b24562259363bd90877d8e454f297bf235782c459539959 [Private key: 115792089237316195423570985008687907852837564279074904382605163141518161494332] Validated: k4 matches Public key 5: 04337b52e3acda49dff79f54fbccb94671a045693ee0d097cc138c694695a836682753ddd9c91a1 c292b24562259363bd90877d8e454f297bf235782c459539959 [Private key: 42993776658852406332510862600000713451036840780736873822127223568596333088584] Validated: k5 matches Public key 6: 049cf8cecf391e958cb2ac03df28ea6865772f120342cdcd7c20cac14eb816d5e32753ddd9c91a1 c292b24562259363bd90877d8e454f297bf235782c459539959 [Private key: 72798312578463789091060122408687194401800723498338030560477939572921828405758] Validated: k6 matches
Sum of private keys for y1 = 115792089237316195423570985008687907852837564279074904382605163141518161494337 (should be n or 2n) Sum of private keys for y2 = 231584178474632390847141970017375815705675128558149808765210326283036322988674 (should be n or 2n)
would you share the code or script for above output?
|
|
|
|
Geshma
Newbie
Offline
Activity: 19
Merit: 0
|
 |
March 15, 2025, 01:44:53 PM |
|
from ecdsa.ellipticcurve import Point from ecdsa.curves import SECP256k1
# Secp256k1 parameters curve = SECP256k1.curve p = curve.p() n = SECP256k1.order G = SECP256k1.generator
# Endomorphism constants beta = 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee lmbda = 0x5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72 beta2 = (beta * beta) % p lmbda2 = (lmbda * lmbda) % n
def endomorphism(P, beta_val): """Apply x-coordinate endomorphism with given beta""" return Point(curve, (beta_val * P.x()) % p, P.y(), order=n)
def negate_point(P): """Negate point by flipping y-coordinate""" return Point(curve, P.x(), (-P.y()) % p, order=n)
def format_key(P): """Format point as uncompressed public key""" return f'04{P.x():064x}{P.y():064x}'
# Input private key k = 5
# Base point P = k * G
# Generate all 6 keys keys = [ # Original y group (P, k), (endomorphism(P, beta), (k * lmbda) % n), (endomorphism(P, beta2), (k * lmbda2) % n), # Negated y group (negate_point(P), (n - k) % n), (negate_point(endomorphism(P, beta)), (n - (k * lmbda)) % n), (negate_point(endomorphism(P, beta2)), (n - (k * lmbda2)) % n) ]
# Print results print(f"Uncompressed public key: {format_key(P)}\n")
print("Three x values:") print(f"x1 = {P.x()}") print(f"x2 = {endomorphism(P, beta).x()}") print(f"x3 = {endomorphism(P, beta2).x()}\n")
print("Two y values:") print(f"y1 = {P.y()}") print(f"y2 = {negate_point(P).y()}\n")
print("Six public keys with private keys:") for i, (point, priv) in enumerate(keys, 1): print(f"Public key {i}: {format_key(point)} [Private key: {priv}]") print(f" Validated: {point == priv * G}")
sum_y1 = sum(keys[1] for i in range(3)) sum_y2 = sum(keys[1] for i in range(3,6))
print(f"\nSum for y1: {sum_y1} (n = {n})") print(f"Sum for y2: {sum_y2} (2n = {2*n})")
|
|
|
|
mjojo
Newbie
Offline
Activity: 77
Merit: 0
|
 |
March 16, 2025, 12:50:10 AM |
|
from ecdsa.ellipticcurve import Point from ecdsa.curves import SECP256k1
# Secp256k1 parameters curve = SECP256k1.curve p = curve.p() n = SECP256k1.order G = SECP256k1.generator
# Endomorphism constants beta = 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee lmbda = 0x5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72 beta2 = (beta * beta) % p lmbda2 = (lmbda * lmbda) % n
def endomorphism(P, beta_val): """Apply x-coordinate endomorphism with given beta""" return Point(curve, (beta_val * P.x()) % p, P.y(), order=n)
def negate_point(P): """Negate point by flipping y-coordinate""" return Point(curve, P.x(), (-P.y()) % p, order=n)
def format_key(P): """Format point as uncompressed public key""" return f'04{P.x():064x}{P.y():064x}'
# Input private key k = 5
# Base point P = k * G
# Generate all 6 keys keys = [ # Original y group (P, k), (endomorphism(P, beta), (k * lmbda) % n), (endomorphism(P, beta2), (k * lmbda2) % n), # Negated y group (negate_point(P), (n - k) % n), (negate_point(endomorphism(P, beta)), (n - (k * lmbda)) % n), (negate_point(endomorphism(P, beta2)), (n - (k * lmbda2)) % n) ]
# Print results print(f"Uncompressed public key: {format_key(P)}\n")
print("Three x values:") print(f"x1 = {P.x()}") print(f"x2 = {endomorphism(P, beta).x()}") print(f"x3 = {endomorphism(P, beta2).x()}\n")
print("Two y values:") print(f"y1 = {P.y()}") print(f"y2 = {negate_point(P).y()}\n")
print("Six public keys with private keys:") for i, (point, priv) in enumerate(keys, 1): print(f"Public key {i}: {format_key(point)} [Private key: {priv}]") print(f" Validated: {point == priv * G}")
sum_y1 = sum(keys[1] for i in range(3)) sum_y2 = sum(keys[1] for i in range(3,6))
print(f"\nSum for y1: {sum_y1} (n = {n})") print(f"Sum for y2: {sum_y2} (2n = {2*n})")
Thankyou @Geshma
|
|
|
|
|