Author

Topic: Determining the positivity or negativity of a Bitcoin public key (Read 486 times)

jr. member
Activity: 37
Merit: 68
This type of approach are often seen as an attempt to relate between the public key and (even/odd) privatekey in last few years.

You can make an experiment. Generate from 1 to 1billion all privatekeys, their corresponding publickey. Isolate them into 2 groups based on 02 or 03. Now try to relate this +/- pubkey observation to the PrivateKey. You will get nothing.

Otherwise anyone could have broken any 256 bit pubkey in just 256 loops of conditional division by 2 untill reach to 1.
newbie
Activity: 5
Merit: 168
In math 1 / 2 = 0.5
In secp256k1 curve scalars 1 / 2 mod N = 57896044618658097711785492504343953926418782139537452191302581570759080747169
57896044618658097711785492504343953926418782139537452191302581570759080747169 is multiplicative_inverse of 2
We can imagine 57896044618658097711785492504343953926418782139537452191302581570759080747169 to be 0.5
In math 4 * 0.5  = 2
In secp256k1 point_multiplication(4G, 57896044618658097711785492504343953926418782139537452191302581570759080747169) = 2G
In reality all secp256k1 scalar values are positive integers.
Mathematically we can mind them as whole numbers, integers, rationals, whatever.
The same goes for public keys.
In reality x,y-coordinates of secp256k1 curve are all positive values and all curve points are on the first quadrant of Coordinate Plane.
Mathematically and geometrically we have a different view.
member
Activity: 239
Merit: 53
New ideas will be criticized and then admired.
Final Summary
Negative public key values exist mathematically, but they are abstracted away in Bitcoin's implementation. This abstraction leads to the common misconception that public keys cannot be negative.

I am not assuming that a coordinate has no positive or negative values ​​in the intermediate process, but that it does not indicate an order relationship between public and private keys. Both are simply two possible points on the curve of a coordinate, i.e. there is no relationship in this regard to their order. If there were a way to identify them, it would not be through this.
jr. member
Activity: 32
Merit: 3
By analyzing the public key values alone, the program effectively narrows down the characteristics of the private keys, aiding in identifying whether the private key is positive or negative.

1. Private Key and Public Key Basics
Private Key:
In Bitcoin, a private key is defined as a positive integer between 1 and n-1, where n is the order of the curve used. For the secp256k1 curve, n = 2^256 - 2^32 - 977. Therefore, private keys are always positive integers and cannot have a negative sign.

Public Key:
A private key generates a public key by performing elliptic curve multiplication on the secp256k1 curve. The public key is represented as a point (x, y) on the elliptic curve, where x and y are integers. Mathematically, these integers can be either positive or negative.

2. Misunderstanding About the Negative Sign
Since private keys cannot be negative, some developers mistakenly assume that public keys also cannot have negative values.
However, the public key (x, y) lies on the elliptic curve defined by the equation:
y^2 = x^3 + 7

For any given x, the equation ensures there are two possible y values: one positive and one negative. This is due to the symmetric nature of the elliptic curve about the x-axis.

3. Why Public Keys Are Thought to Lack Negative Signs
In Bitcoin, public keys are stored and transmitted in specific formats, which often abstract away the negative sign:

Compressed Public Key Format:

In the compressed format, only the x coordinate is stored, along with a prefix that indicates the sign of y (even or odd).
The prefix is 02 if y is even and 03 if y is odd.
For example, a public key (x, y) where y > 0 or y < 0 is reduced to x and a single bit of information about the parity of y.
Uncompressed Public Key Format:

In the uncompressed format, both x and y are included. However, the protocol does not store negative integers directly. Instead, it uses the absolute values of x and y and assumes a positive representation.
Due to these storage and transmission methods, the negative sign of y is not explicitly visible. This abstraction leads to the mistaken belief that public keys never have negative components.

4. Conclusion: Public Keys Can Correspond to Negative Values
Public keys have two perspectives:

Mathematical Perspective:
Public keys (x, y) are points on the elliptic curve. For a given x, there are always two possible y values (one positive and one negative), meaning the negative version of the public key exists mathematically.

Bitcoin Protocol Perspective:
The Bitcoin protocol stores and transmits public keys in formats that either compress or use absolute values, making negative signs implicit rather than explicit. This is why many developers mistakenly believe public keys cannot have negative values.

Final Summary
Negative public key values exist mathematically, but they are abstracted away in Bitcoin's implementation. This abstraction leads to the common misconception that public keys cannot be negative.

This plain text version is free of special characters and encoding issues, ensuring it can be copied and pasted without any problems.
member
Activity: 239
Merit: 53
New ideas will be criticized and then admired.
By analyzing the public key values alone, the program effectively narrows down the characteristics of the private keys, aiding in identifying whether the private key is positive or negative.

A very simple example: imagine ECC as a clock with hands. After 12 comes 1; if you subtract 5 hours from 3, it would be 10, meaning it will never go negative. This is the concept of a modulo in mathematics. That is, the result will always remain within a defined range, in this case from 1 to 12, and will never yield a negative result. ECC doesn’t work exactly the same, but the concept is very similar when adding and subtracting points.
legendary
Activity: 4578
Merit: 3526
...
This program aims to test whether it is possible to narrow down the range of private key values based on the public key by determining if the result of subtracting a private key from a public key is positive or negative.

  • 1. You can't subtract a private key from a public key. A private key is a scalar. A public key is a vector.
  • 2. A private key doesn't have a sign. It is a number between 1 and 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140
  • 3. There is a major error in your generate_public_key function. The prefix of a compressed public key is determined only by the value of the public key.
jr. member
Activity: 32
Merit: 3
Code:
import random
import ecdsa
import binascii

# Define the range
def generate_random_values():
    a = random.randint(2**134, 2**135)
    am = 10**37
    b = a - am

    # Set pma and pmb: both values should have the same sign
    sign = random.choice([1, -1])  # Set both as either positive or negative
    pma = sign * a
    pmb = sign * b

    return a, b, am, pma, pmb

# Define N (order of the secp256k1 curve)
N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141

# Function to generate a public key from a private key
def generate_public_key(private_key_int):
    # Convert the private key to a 32-byte format
    private_key_bytes = abs(private_key_int).to_bytes(32, byteorder="big", signed=True)
    
    # Generate the elliptic curve public key (secp256k1)
    sk = ecdsa.SigningKey.from_string(private_key_bytes, curve=ecdsa.SECP256k1)
    vk = sk.verifying_key
    
    # Create uncompressed public key format
    public_key_bytes_uncompressed = b"\x04" + vk.to_string()
    
    # Determine the compressed public key's prefix based on the private key's sign
    if private_key_int < 0:
        public_key_bytes_compressed = (
            b"\x03" + vk.to_string()[:32] if vk.to_string()[-1] % 2 == 0 else b"\x02" + vk.to_string()[:32]
        )
    else:
        public_key_bytes_compressed = (
            b"\x02" + vk.to_string()[:32] if vk.to_string()[-1] % 2 == 0 else b"\x03" + vk.to_string()[:32]
        )
    
    # Convert the public keys to hexadecimal strings
    public_key_uncompressed = binascii.hexlify(public_key_bytes_uncompressed).decode()
    public_key_compressed = binascii.hexlify(public_key_bytes_compressed).decode()
    
    return public_key_uncompressed, public_key_compressed

# Adjust private key representation
def adjust_private_key(private_key_int):
    if private_key_int < 0:
        adjusted_key = N + private_key_int
        return f"0x{adjusted_key:064x}"
    else:
        return str(private_key_int)

# Generate and output results 10 times
for i in range(1, 11):
    print(f"\n=== Random Output {i} ===")
    a, b, am, pma, pmb = generate_random_values()
    public_key_a_uncompressed, public_key_a_compressed = generate_public_key(pma)
    public_key_b_uncompressed, public_key_b_compressed = generate_public_key(pmb)

    print("a:", a)
    print("b:", b)
    print("am:", am)
    print("pma (Private Key a):", adjust_private_key(pma))
    print("pmb (Private Key b):", adjust_private_key(pmb))

    print("public_key_a (Compressed Public Key a):", public_key_a_compressed)
    print("public_key_b (Compressed Public Key b):", public_key_b_compressed)

Purpose of the Program
This program aims to test whether it is possible to narrow down the range of private key values based on the public key by determining if the result of subtracting a private key from a public key is positive or negative.

For example, if the private key is 1000, the corresponding public key is maina.

maina - private_key(800) = sub1(public_key(+200))
If sub1 can be distinguished as positive or negative, it becomes possible to narrow down the range of private key values associated with maina.
Reason for Development
This program was developed to test the theory that if it is possible to distinguish between positive and negative public keys after subtracting a private key value, it becomes easier to find the range of the private key based on the public key.

Program Conditions

The condition a > b must always hold.
The value am can be adjusted by the problem setter within the range 10^35 to 10^38.
Program Features
After running the program, if only the public key is provided, it can determine whether the result is positive or negative.

This program generates 10 sets of public_key_a and public_key_b, and it can identify with 100% accuracy whether each value is positive or negative.

While the program itself outputs both the private keys and the corresponding public keys during execution, only the public key values need to be provided to determine whether the result is positive or negative. This means that as long as you have the public keys, the program can distinguish the sign of the resulting public key values without requiring any additional information about the private keys.

By analyzing the public key values alone, the program effectively narrows down the characteristics of the private keys, aiding in identifying whether the private key is positive or negative.
?
Activity: -
Merit: -
I saved your contact, I will write to you during the day, thank you
?
Activity: -
Merit: -
Thank you for your response. Is it possible to communicate with you via private messages? I believe we could find common ground on this topic, but I can't send you a private message because I'm new to this forum.
jr. member
Activity: 32
Merit: 3
Hello, I read your post, "Determining the positivity or negativity of a Bitcoin public key," and I find this topic quite interesting. I would like to know what exactly you have discovered on this matter so far, if it’s not too much trouble.


1. Bitcoin public keys consist of both positive and negative values.

2.Theoretically, tracking Bitcoin private keys can be attempted through factorization, but the numbers involved are too large to make this feasible.

3.If an app existed that could distinguish between the positive and negative aspects of a public key,
all private keys could potentially be discovered within 5 minutes. However, no method for such a distinction has been identified to date.

Here is a site where you can study the basics of positive and negative values:
https://royalforkblog.github.io/2014/09/04/ecc/



Positive:  1×G=(0,2)
Negative: 30×G=(0,27)

Positive: 2×G=(6,17)
Negative: 29×G=(6,12)

This applies to all Bitcoin as well.
Refer to the illustration for more details.
https://ibb.co/y5VjVm5
?
Activity: -
Merit: -
Hello, I read your post, "Determining the positivity or negativity of a Bitcoin public key," and I find this topic quite interesting. I would like to know what exactly you have discovered on this matter so far, if it’s not too much trouble.
jr. member
Activity: 32
Merit: 3
@odolvlobo
@kTimesG

I would like to apologize to both of you.
The part you pointed out as an error was indeed an error.
I was wrong to think that as long as the result was correct, it would be fine.
Thank you to everyone who showed interest.
The issue has been resolved. Thank you!
member
Activity: 165
Merit: 26
Code:
   # Determine the first byte of the compressed public key based on the private key's sign
    if private_key_int < 0:
        public_key_bytes_compressed = (
            b"\x03" + vk.to_string()[:32] if vk.to_string()[-1] % 2 == 0 else b"\x02" + vk.to_string()[:32]
        )
    else:
        public_key_bytes_compressed = (
            b"\x02" + vk.to_string()[:32] if vk.to_string()[-1] % 2 == 0 else b"\x03" + vk.to_string()[:32]
        )

You code is incorrect. The 0x02, 0x03 prefixes are based only on the value of the public key.

Furthermore, a valid secp256k1 private key is an integer in the range 1 to FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140, so testing if it is less than 0 should always return false. If your test returns true, then the private key is invalid or there is a bug in your code.


Since the program itself knows the private key, the public key output result is 100% accurate.
There are no errors in the program.
Please check the private key and the outputted public key.

So you've been told twice already that you're doing things incorrectly, but you insist on it being 100% correct and error-free. Why do you need our opinion in that case?

Public keys for private keys "-1" and N-1 are identical, while your code messes up their compressed representation (since you have a logical contradiction at the reasoning layer, since private keys don't have a sign, since a modular interval doesn't have negative values). So before all else, if your code was Windows 95, this would become a BSOD of the brain.
jr. member
Activity: 32
Merit: 3
Code:
   # Determine the first byte of the compressed public key based on the private key's sign
    if private_key_int < 0:
        public_key_bytes_compressed = (
            b"\x03" + vk.to_string()[:32] if vk.to_string()[-1] % 2 == 0 else b"\x02" + vk.to_string()[:32]
        )
    else:
        public_key_bytes_compressed = (
            b"\x02" + vk.to_string()[:32] if vk.to_string()[-1] % 2 == 0 else b"\x03" + vk.to_string()[:32]
        )

You code is incorrect. The 0x02, 0x03 prefixes are based only on the value of the public key.

Furthermore, a valid secp256k1 private key is an integer in the range 1 to FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140, so testing if it is less than 0 should always return false. If your test returns true, then the private key is invalid or there is a bug in your code.


Since the program itself knows the private key, the public key output result is 100% accurate.
There are no errors in the program.
Please check the private key and the outputted public key.
legendary
Activity: 4578
Merit: 3526
Code:
   # Determine the first byte of the compressed public key based on the private key's sign
    if private_key_int < 0:
        public_key_bytes_compressed = (
            b"\x03" + vk.to_string()[:32] if vk.to_string()[-1] % 2 == 0 else b"\x02" + vk.to_string()[:32]
        )
    else:
        public_key_bytes_compressed = (
            b"\x02" + vk.to_string()[:32] if vk.to_string()[-1] % 2 == 0 else b"\x03" + vk.to_string()[:32]
        )

You code is incorrect. The 0x02, 0x03 prefixes are based only on the value of the public key.

Furthermore, a valid secp256k1 private key is an integer in the range 1 to FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140, so testing if it is less than 0 should always return false. If your test returns true, then the private key is invalid or there is a bug in your code.
member
Activity: 165
Merit: 26
When |pma| > |pmb|, the positivity or negativity can be determined with 100% accuracy, but when |pma| < |pmb|, errors occur in determining positivity or negativity. I am looking for someone to collaborate on this issue.

1. There's no such thing as a negative public key or negative private key.
2. There's no relation between the bits of a private key and the bits of a public key, otherwise ECC would be broken. Your code fails the very fundamentals of how ECC works.
3. You have errors because you wrote that bunch of code without understanding what ECC is all about, and so of course you get errors, since it doesn't make sense even before you would write it on paper as pseudo-code, let alone as a Python script.
4. It works when |pma| > |pmb| because this is how you created it to work (as it doesn't really respect ECC fundamentals, rather some dubious creation of strings which are definitely not respecting the correct private key to public key relation); hence, since it is written in such a way to produce results based on what you wanted it to do, what else would you expect in the other cases? Magic?
5. Good luck on finding a collaborator to help you fix the "errors".
6. Public key prefixes indicate the Y parity (the least significant bit value), not the private key being in the lower or upper half of the scalar field. Else it would be a backdoor/leak in the ECC system. See point 2.
jr. member
Activity: 32
Merit: 3
Due to the nature of elliptic curves over finite fields, (when using secure parameters) it is not possible (or at least, no one knows how) to take the public key and infer any information about the private key.

===>
I am not trying to find out the private key; I want a program that can distinguish the positivity or negativity of the public key.
member
Activity: 75
Merit: 11
This program generates public keys from randomly created private keys using elliptic curve cryptography, specifically the secp256k1 curve used in Bitcoin. The private keys (pma and pmb) are set with the same sign, either both positive or both negative. Based on the sign of each private key, the program outputs corresponding compressed and uncompressed public keys. The compressed public keys’ prefixes (0x02 or 0x03) are adjusted according to whether the private key is positive or negative.

There is a program that determines whether the private key is positive or negative based solely on the generated public key output.

program

import random
import ecdsa
import binascii

# Define the range
a = random.randint(2**134, 2**135)
am = 10**37
b = a - am

# Set pma and pmb: both values should have the same sign
sign = random.choice([1, -1])  # Set both as either positive or negative
pma = sign * a
pmb = sign * b

# Function to generate a public key from a private key
def generate_public_key(private_key_int):
    # Convert the private key to a 32-byte format
    private_key_bytes = abs(private_key_int).to_bytes(32, byteorder="big", signed=True)
    
    # Generate the elliptic curve public key (secp256k1)
    sk = ecdsa.SigningKey.from_string(private_key_bytes, curve=ecdsa.SECP256k1)
    vk = sk.verifying_key
    
    # Create uncompressed public key format
    public_key_bytes_uncompressed = b"\x04" + vk.to_string()
    
    # Determine the compressed public key's prefix based on the private key's sign
    if private_key_int < 0:
        public_key_bytes_compressed = (
            b"\x03" + vk.to_string()[:32] if vk.to_string()[-1] % 2 == 0 else b"\x02" + vk.to_string()[:32]
        )
    else:
        public_key_bytes_compressed = (
            b"\x02" + vk.to_string()[:32] if vk.to_string()[-1] % 2 == 0 else b"\x03" + vk.to_string()[:32]
        )
    
    # Convert the public keys to hexadecimal strings
    public_key_uncompressed = binascii.hexlify(public_key_bytes_uncompressed).decode()
    public_key_compressed = binascii.hexlify(public_key_bytes_compressed).decode()
    
    return public_key_uncompressed, public_key_compressed

# Generate public keys using pma and pmb as private keys
public_key_a_uncompressed, public_key_a_compressed = generate_public_key(pma)
public_key_b_uncompressed, public_key_b_compressed = generate_public_key(pmb)

# Output the results
print("a:", a)
print("b:", b)
print("am:", am)
print("pma (Private Key a):", pma)
print("pmb (Private Key b):", pmb)
print("public_key_a (Uncompressed Public Key a):", public_key_a_uncompressed)
print("public_key_a (Compressed Public Key a):", public_key_a_compressed)
print("public_key_b (Uncompressed Public Key b):", public_key_b_uncompressed)
print("public_key_b (Compressed Public Key b):", public_key_b_compressed)

It is possible to determine the positivity or negativity if the final output values of pma and pmb from the current program are provided.

When |pma| > |pmb|, the positivity or negativity can be determined with 100% accuracy, but when |pma| < |pmb|, errors occur in determining positivity or negativity. I am looking for someone to collaborate on this issue.


Due to the nature of elliptic curves over finite fields, (when using secure parameters) it is not possible (or at least, no one knows how) to take the public key and infer any information about the private key.
jr. member
Activity: 32
Merit: 3
This program generates public keys from randomly created private keys using elliptic curve cryptography, specifically the secp256k1 curve used in Bitcoin. The private keys (pma and pmb) are set with the same sign, either both positive or both negative. Based on the sign of each private key, the program outputs corresponding compressed and uncompressed public keys. The compressed public keys’ prefixes (0x02 or 0x03) are adjusted according to whether the private key is positive or negative.

There is a program that determines whether the private key is positive or negative based solely on the generated public key output.

program

import random
import ecdsa
import binascii

# Define the range
a = random.randint(2**134, 2**135)
am = 10**37
b = a - am

# Set pma and pmb: both values should have the same sign
sign = random.choice([1, -1])  # Set both as either positive or negative
pma = sign * a
pmb = sign * b

# Function to generate a public key from a private key
def generate_public_key(private_key_int):
    # Convert the private key to a 32-byte format
    private_key_bytes = abs(private_key_int).to_bytes(32, byteorder="big", signed=True)
    
    # Generate the elliptic curve public key (secp256k1)
    sk = ecdsa.SigningKey.from_string(private_key_bytes, curve=ecdsa.SECP256k1)
    vk = sk.verifying_key
    
    # Create uncompressed public key format
    public_key_bytes_uncompressed = b"\x04" + vk.to_string()
    
    # Determine the compressed public key's prefix based on the private key's sign
    if private_key_int < 0:
        public_key_bytes_compressed = (
            b"\x03" + vk.to_string()[:32] if vk.to_string()[-1] % 2 == 0 else b"\x02" + vk.to_string()[:32]
        )
    else:
        public_key_bytes_compressed = (
            b"\x02" + vk.to_string()[:32] if vk.to_string()[-1] % 2 == 0 else b"\x03" + vk.to_string()[:32]
        )
    
    # Convert the public keys to hexadecimal strings
    public_key_uncompressed = binascii.hexlify(public_key_bytes_uncompressed).decode()
    public_key_compressed = binascii.hexlify(public_key_bytes_compressed).decode()
    
    return public_key_uncompressed, public_key_compressed

# Generate public keys using pma and pmb as private keys
public_key_a_uncompressed, public_key_a_compressed = generate_public_key(pma)
public_key_b_uncompressed, public_key_b_compressed = generate_public_key(pmb)

# Output the results
print("a:", a)
print("b:", b)
print("am:", am)
print("pma (Private Key a):", pma)
print("pmb (Private Key b):", pmb)
print("public_key_a (Uncompressed Public Key a):", public_key_a_uncompressed)
print("public_key_a (Compressed Public Key a):", public_key_a_compressed)
print("public_key_b (Uncompressed Public Key b):", public_key_b_uncompressed)
print("public_key_b (Compressed Public Key b):", public_key_b_compressed)

It is possible to determine the positivity or negativity if the final output values of pma and pmb from the current program are provided.

When |pma| > |pmb|, the positivity or negativity can be determined with 100% accuracy, but when |pma| < |pmb|, errors occur in determining positivity or negativity. I am looking for someone to collaborate on this issue.
Jump to: