To get double R you need original k value add in original z value itself
s_add = 1 (its up to you)
k = (your_k value)
z_add = k * s_add
r2 = r1
s2 = s1 + s_add
z2 = z1 + z_add
this is impossible to solve for recreating unknown K value
if we want to solve signature in todays technology, lattice attack and polynomials attack but in bruteforce way
Question: is your shifting method same pubkey recovered Y = (R*s-G*m)/r ??
your shifting method is interesting
If you look at the original formula I mention above, once you get the different a and b, it leads to the same r but different s and z. Typically if we use the conventional method of using same K nonce for the same r but different s and z, we still get different u1 and U2 values. Now I'm just starting from u1 and U2 first. So take the conventional method, get it's u1 and U2 values of two signatures that has the same r but different s and z, compute it's u1 and U2, then u1=a and U2 = b. You get the same signature. But in order for us who don't have the private key or K nonce to get to a valid same pubkey signatures. We use the shifting method. Where after getting the aG and bQ value, we use a random t value to get aG2 = aG + tG and bQ2 = bQ - tG.
This gives us the shifting value that leads to the same r.
r =aG + bQ and r = aG2 + bQ2.
Then to compute it's a and b value. It's just a2 = a + t , that's equal to aG when scalar multiplied.
now you are left with looking for b2. the formula to get b2 is ALMOST opposite but similar. then now u have a different a2 and b2 value that leads to the same r but due to its a2 and b2 value being different from a and b value , when the same formula is applied which is s= r * inv(b,n) and z = a * s (b, N) % n, we get the same r value but different s and z value that is valid for the same pubkey
To get double R you need original k value add in original z value itself
s_add = 1 (its up to you)
k = (your_k value)
z_add = k * s_add
r2 = r1
s2 = s1 + s_add
z2 = z1 + z_add
this is impossible to solve for recreating unknown K value
if we want to solve signature in todays technology, lattice attack and polynomials attack but in bruteforce way
Question: is your shifting method same pubkey recovered Y = (R*s-G*m)/r ??
your shifting method is interesting
Hey man... I replied wrongly. I meant to reply that to a person in my inbox. And yes...it does gives the same valid public key.
Here is the code. i had remove in method 1 how to get to b2 and in method 2 starting with random b value obviously for security reasons.
from random import SystemRandom
P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
Gy = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
G = (Gx, Gy)
pubkey_x = 96953063599923793356065023910106792740284067034392039319548634253844580007549
pubkey_y = 24213599371259323050868340559734230940120001082991520973823206482901563403021
Q = (pubkey_x % P, pubkey_y % P)
def modinv(a, m):
if a < 0:
a = (a % m + m) % m
g, x, _ = extended_gcd(a, m)
if g != 1:
raise Exception('Modular inverse does not exist')
return x % m
def extended_gcd(a, b):
if a == 0:
return b, 0, 1
gcd, x1, y1 = extended_gcd(b % a, a)
x = y1 - (b // a) * x1
y = x1
return gcd, x, y
def point_add(p1, p2):
if p1 is None:
return p2
if p2 is None:
return p1
x1, y1 = p1
x2, y2 = p2
x1, y1 = x1 % P, y1 % P
x2, y2 = x2 % P, y2 % P
if x1 == x2:
if y1 == y2:
s = (3 * x1 * x1 * modinv(2 * y1, P)) % P
else:
return None
else:
s = ((y2 - y1) * modinv((x2 - x1) % P, P)) % P
x3 = (s * s - x1 - x2) % P
y3 = (s * (x1 - x3) - y1) % P
return (x3, y3)
def point_neg(p):
x, y = p
return (x, (-y) % P)
def point_mul(point, scalar):
result = None
current = point
while scalar > 0:
if scalar & 1:
result = point_add(result, current)
current = point_add(current, current)
scalar >>= 1
return result
def verify_sig(r, s, z):
s_inv = modinv(s, N)
u1 = (z * s_inv) % N
u2 = (r * s_inv) % N
u1G = point_mul(G, u1)
u2Q = point_mul(Q, u2)
P_ver = point_add(u1G, u2Q)
if P_ver is None:
return False
return P_ver[0] % N == r
print("\n==================== ORIGINAL METHOD ====================")
rand = SystemRandom()
a = rand.randrange(1, N)
b = rand.randrange(1, N)
aG = point_mul(G, a)
bQ = point_mul(Q, b)
R = point_add(aG, bQ)
r = R[0] % N
s = r * modinv(b, N) % N
z = a * s % N
print(f"a = {a:064x}")
print(f"b = {b:064x}")
print(f"r = {r:064x}")
print(f"s = {s:064x}")
print(f"z = {z:064x}")
print(f"Qx = {Q[0]:064x}")
print(f"Qy = {Q[1]:064x}")
valid = verify_sig(r, s, z)
print(f"Signature Valid? = {valid}")
print("\n==================== METHOD 1: SHIFTING aG & bQ ====================")
t = rand.randrange(1, N)
tG = point_mul(G, t)
aG2 = point_add(aG, tG)
b2Q = point_add(bQ, point_neg(tG))
R2 = point_add(aG2, b2Q)
r2 = R2[0] % N
#calculate a2 and verify
a2 = (a + t) % N
a2G = point_mul(G, a2)
print(f"t = {t:064x}")
print(f"tG = {tG[0]:064x}")
print(f"a2 = {a2:064x}")
print(f"aG2 = {aG2[0]:064x}")
print(f"b2Q = {b2Q[0]:064x}")
print(f"r2 = {r2:064x}")
print(f"Same r? {r == r2}")
print(f"a2*G = a2G = {a2G[0]:064x}")
print(f"Verification")
print(f"a2G = aG2 value? {a2G == aG2}")