dalek-cryptography / curve25519-dalek

A pure-Rust implementation of group operations on Ristretto and Curve25519
Other
910 stars 470 forks source link

Request: Add FieldElement::as_bytes() function #69

Closed heartsucker closed 7 years ago

heartsucker commented 7 years ago

I'm currently trying to get ring's Ed25519 public keys to interface correctly with some system that uses Java/BouncyCastle. For the keys to have the correct format for the SubjectPublicKeyInfo with OID 1.2.840.10045.2.1, I need to append the X and Y coordinates to each other. It would be best to use the CompressedEdwardsY::decompress function to give me an ExtendedPoint where I can extract the values I need. Currently the solution would just be to copy/paste the current decompress function and replace the last line with what I need.

Anyway.

Could a function be added that gives me access to the raw bytes of a FieldElement?

isislovecruft commented 7 years ago

Hi @heartsucker!

I'm sorry that I don't know anything about that OID but I am guessing that what they mean by "append the X and Y coordinates to each other" what they actually are referring to is the x- and y-coordinates in affine coordinates (assuming a Weierstrass model???). The points within an ed25519_dalek::PublicKey are curve25519_dalek::curve::ExtendedPoints, so in extended homogeneous twisted Edwards representation, which is projective. (Otherwise appending x and y makes no sense, as it wouldn't add any additional information.)

There's the FieldElement.to_bytes() method, would that work for your use case to do FieldElement.to_bytes().as_ref() or such? The internal representation of a FieldElement is implementation specific though, and as such likely not portable.

heartsucker commented 7 years ago

I think they really are just appending the coordinates to each other. This is the method from ECPoint.java.

    public byte[] getEncoded(boolean compressed)
    {
        if (this.isInfinity())
        {
            return new byte[1];
        }

        ECPoint normed = normalize();

        byte[] X = normed.getXCoord().getEncoded();

        if (compressed)
        {
            byte[] PO = new byte[X.length + 1];
            PO[0] = (byte)(normed.getCompressionYTilde() ? 0x03 : 0x02);
            System.arraycopy(X, 0, PO, 1, X.length);
            return PO;
        }

        byte[] Y = normed.getYCoord().getEncoded();

        byte[] PO = new byte[X.length + Y.length + 1];
        PO[0] = 0x04;
        System.arraycopy(X, 0, PO, 1, X.length);
        System.arraycopy(Y, 0, PO, X.length + 1, Y.length);
        return PO;
    }

Otherwise appending x and y makes no sense, as it wouldn't add any additional information.

Yes, this is true. However this OID is for generic elliptic curves, so I think the idea was to split it into the x and y coordinates to make it use the same format for all keys for all curves. But the actual why isn't so important as that's what I have to deal with.

It also looks like there's only FieldElement32::to_bytes, but not the same function for the generic sized FieldElement. Since the docs on FieldElement32::to_bytes say that the bytes are canonical, would it be possible to add an Info<FieldElement32> for FieldElement to allow someone to get that representation. Or am I a missing a compiler flag or some intermediate step?

heartsucker commented 7 years ago

Got back to the office and realized FieldElement is just an alias for FieldElement32. Closing this as resolved.

briansmith commented 7 years ago

However this OID is for generic elliptic curves

Please don't make software that uses that encoding of Ed25519/X25519 public keys. We intentionally standardized the alternate, now-standard, encoding, and nobody wants to support the generic encoding.

heartsucker commented 7 years ago

I agree. I'm interfacing with an application that uses this encoding, so that's what I'm stuck using.