1

As per https://crypto.stackexchange.com/questions/18105/how-does-recovering-the-public-key-from-an-ecdsa-signature-work, I should be able to recover an ECDSA public key if I have a signature and the message it is signing. Are there any examples as to how to get this information using BouncyCastle and Java? If not, could someone walk me through the basics of how to implement it?

If it helps, this is how I'm signing the message:

public static String signData(PrivateKey privateKey, String in) {
    Security.addProvider(new BouncyCastleProvider());
    String out;
    Signature sig;
    try {
        sig = Signature.getInstance("SHA256withECDSA","BC");
        sig.initSign(privateKey);
        byte[] inBytes = in.getBytes();
        sig.update(inBytes);
        byte[] sigFinal = sig.sign();
        out = getHex(sigFinal);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
    return out;
}

I guess my biggest issue is I don't know how java Signatures are encoded and outputted. If anyone could shed any light on that it would be appreciated.

Lev Knoblock
  • 611
  • 2
  • 6
  • 20
  • That SX article gives the literal formula. You need some tools to implement it, though. Namely, you need a library that can do arithmetic on the elliptic curve (point add, scalar-point multiply); you also need the ability to do modular arithmetic with integers. Looks like bouncy-castle hooks you up with the right tools to do the former (http://people.eecs.berkeley.edu/~jonah/lcrypto/org/bouncycastle/math/ec/ECPoint.html), and Java's big-int class can do the latter. There are articles on recovering the y coordinate(s) given the x-coord, and curve params. – lockcmpxchg8b Mar 13 '18 at 04:18
  • It's probably also helpful to note that (Integer times Point = Point), and (Point +/- Point = Point)...everything lower-case in that SX article's first answer is an integer, everything upper-case is a Point. When you see a superscipt of -1, it means modular inverse (where the modulus is the order of the generator of the curve, an Integer) `java.math.BigInteger` implements this as `modInverse`. – lockcmpxchg8b Mar 13 '18 at 04:24
  • @lockcmpxchg8b My issue is that I don't know how to process my signature into the points that the other article mentions, and I don't fully understand the formula given. If that could be explained it a bit more detail, that would be very helpful. – Lev Knoblock Mar 13 '18 at 07:04
  • Okay. `r` is a component of the signature. It is the the 'x' coordinate of the point R. The SX article points out that there are typically two points on the curve for any given x coordinate, and it labels them R and R', only one of which is the true R. Most curves use the short Weierstrass form: `Y^2 = X^3 + aX + b` (where they only specify `a` and `b`). This equations relates the x and y coordinates of a point "on the curve", so you can compute the y coordinate by computing the RHS, then taking the modular square root. (modular sqrt can be ... involved) – lockcmpxchg8b Mar 13 '18 at 07:09
  • `G` is the "generator point" for the curve, and is always specified as part of the curve parameters (right alongside `a` and `b`). `s` is the other component of the signature (alongside `r`), and `z` is the SHA digest, with some of the bits discarded if it's too big. Certicom has published a really nice write-up on computing ECDSA, that will cover the details of how to handle SHA – lockcmpxchg8b Mar 13 '18 at 07:11
  • See: http://www.secg.org/ SEC1 gives the algorithms, SEC2 gives the standard domain parameters. – lockcmpxchg8b Mar 13 '18 at 07:17
  • So how would I go about extracting that from the byte array or the string generated in my signing code? Is it a specific part of the array at all times? Can I just truncate the array to grab that r value? – Lev Knoblock Mar 13 '18 at 07:18
  • Ah, that depends. The output of Bouncy Castle will probably be an ASN.1 coded blob. If you paste it into an ASN.1 decoder, it should show two big-integer fields (among other meta-data like an OID). These will be `r` and `s`. You can find ASN.1 decoder applets on the web. – lockcmpxchg8b Mar 13 '18 at 07:20
  • @lockcmpxchg8b Ok, so I found https://stackoverflow.com/questions/39385718/der-decode-ecdsa-signature-in-java which allowed me to get two values. What do I do with them afterwards? – Lev Knoblock Mar 13 '18 at 07:28
  • Also, just for reference, I'm using secp256k1, so the curve is y^2 = x^3 + 7 – Lev Knoblock Mar 13 '18 at 07:37
  • I just searched for an SO article on reconstructing a point given its x-coord in Java, and can't find one. That's probably your next (and only difficult) task. (So that you can get R/R' from r; there are two candidates precsely because sqrt has two answers) – lockcmpxchg8b Mar 13 '18 at 07:40
  • (I'm surprised your block-chain doesn't publish the public key) – lockcmpxchg8b Mar 13 '18 at 07:43
  • It does, but the goal is to let it extract the public key from the signature and compare it to the public address, instead of storing the signature, key, and address and comparing the key to both. – Lev Knoblock Mar 13 '18 at 07:49
  • Anyway, thanks for the help. I'll see if I can reconstruct the point and convert it to a public address and I'll post an answer here if I figure it out tomorrow. – Lev Knoblock Mar 13 '18 at 07:50
  • @lockcmpxchg8b I guess you could create a compressed point; try and use `02` and `03` as initial byte value, followed by the X-value (of the same size as the order of the curve, e.g. 32 bytes). Then decode and try to verify the signature. – Maarten Bodewes Mar 13 '18 at 13:19
  • @LevKnoblock Were you able to generate public key from signature? If so, could you please point some references used? – Nitish Bhardwaj May 20 '21 at 09:42
  • and solution :)? – Majd TL Dec 21 '21 at 13:47

0 Answers0