Did-core: According to the working draft as of 8 June 2020, raw secp256r1 public keys must be 32-byte long

Created on 20 Jun 2020  路  14Comments  路  Source: w3c/did-core

According to the working draft as of 8 June 2020, 搂5.4 Public Keys says the following.

Secp256r1 public key values MUST either be encoded as a JWK or be encoded as the raw 32-byte public key value encoded in Base58 Bitcoin format using the publicKeyBase58 property.

Shouldn't '32-byte' be '33-byte'? The other byte must exist to store the _y_-value compressed into its parity, just like in the case of secp256k1.

PR exists jose keys pre-cr-p1

Most helpful comment

Why no change? Without the other byte there wouldn't be enough space for the raw public key value.

The reference that @selfissued is probably talking about is this:

https://tools.ietf.org/html/rfc7518#section-6.2.1.2

Which says this:

6.2.1.1.  "crv" (Curve) Parameter

...

   SEC1 [SEC1] point compression is not supported for any of these three
   curves.

6.2.1.2.  "x" (X Coordinate) Parameter

   The "x" (x coordinate) parameter contains the x coordinate for the
   Elliptic Curve point.  It is represented as the base64url encoding of
   the octet string representation of the coordinate, as defined in
   Section 2.3.5 of SEC1 [SEC1].  The length of this octet string MUST
   be the full size of a coordinate for the curve specified in the "crv"
   parameter.  For example, if the value of "crv" is "P-521", the octet
   string must be 66 octets long.

6.2.1.3.  "y" (Y Coordinate) Parameter

   The "y" (y coordinate) parameter contains the y coordinate for the
   Elliptic Curve point.  It is represented as the base64url encoding of
   the octet string representation of the coordinate, as defined in
   Section 2.3.5 of SEC1 [SEC1].  The length of this octet string MUST
   be the full size of a coordinate for the curve specified in the "crv"
   parameter.  For example, if the value of "crv" is "P-521", the octet
   string must be 66 octets long.

which points to here (Section 2.3.5):

http://www.secg.org/sec1-v2.pdf

... and that's what JOSE chooses to do, IIRC -- two separate 32 octet uncompressed values for X and Y for P-256.

If we want to use the compressed form, which we probably do, for the base58btc, then @sammotic is correct and it would be 33 bytes in size:

https://stackoverflow.com/questions/6665353/is-there-a-standardized-fixed-length-encoding-for-ec-public-keys

From Section 2.3.2 of the SEC spec, which is the authority on this:

Elliptic curve points should be converted to octet strings as described in this section. Informally, if point compression is being used, the idea is that the compressed y-coordinate is placed in the leftmost octet of the octet string along with an indication that point compression is on, and the x-coordinate is placed in the remainder of the octet string; otherwise if point compression is off, the leftmost octet indicates that point compression is off, and the remainder of the octet string
contains the x-coordinate followed by the y-coordinate.

Follow the algorithm and you get 33 bytes. @selfissued, are you stating that we should do what JOSE does and express it as uncompressed X and Y values? Note that will take 65 bytes if we use the guidance provided by SEC. If we use compressed form per SEC, it will only take 33 bytes.

The intent here was to use compressed form, and so I suggest that @sammotic is correct and we should make the correction to the spec. I will also note that we may not want to say anything in the spec about key values and instead defer to the Linked Data Security specs to make those assertions... that DID Core is getting these details peppered throughout it is the wrong thing to do, IMHO.

All 14 comments

Yes, the group needs to settle on this and expand to 33 bytes to account for the parity.

this issue is caused by us not just relying on JOSE definitions for JWKs... we should not be addressing key representations on a case by case basis.

related.... there is no registered prefix for P-256... https://github.com/multiformats/multicodec/blob/master/table.csv

These are unsigned values. Prefixing the value with an extra zero would add confusion and cause interop issues. The spec is right to keep the value a 32-byte value.

@selfissued is suggesting no change... waiting for an objection.

These are unsigned values. Prefixing the value with an extra zero would add confusion and cause interop issues. The spec is right to keep the value a 32-byte value.

It's either a 65 byte value (uncompressed, with 0x04 header -- JOSE chose to not use the header and split X and Y apart) or a 33 byte value (with compressed y value as first byte -- JOSE chose to not use this representation). AFAIK, there is no such thing as a single 32 octet encoding that is specified by SEC.

Why no change? Without the other byte there wouldn't be enough space for the raw public key value.

Why no change? Without the other byte there wouldn't be enough space for the raw public key value.

The reference that @selfissued is probably talking about is this:

https://tools.ietf.org/html/rfc7518#section-6.2.1.2

Which says this:

6.2.1.1.  "crv" (Curve) Parameter

...

   SEC1 [SEC1] point compression is not supported for any of these three
   curves.

6.2.1.2.  "x" (X Coordinate) Parameter

   The "x" (x coordinate) parameter contains the x coordinate for the
   Elliptic Curve point.  It is represented as the base64url encoding of
   the octet string representation of the coordinate, as defined in
   Section 2.3.5 of SEC1 [SEC1].  The length of this octet string MUST
   be the full size of a coordinate for the curve specified in the "crv"
   parameter.  For example, if the value of "crv" is "P-521", the octet
   string must be 66 octets long.

6.2.1.3.  "y" (Y Coordinate) Parameter

   The "y" (y coordinate) parameter contains the y coordinate for the
   Elliptic Curve point.  It is represented as the base64url encoding of
   the octet string representation of the coordinate, as defined in
   Section 2.3.5 of SEC1 [SEC1].  The length of this octet string MUST
   be the full size of a coordinate for the curve specified in the "crv"
   parameter.  For example, if the value of "crv" is "P-521", the octet
   string must be 66 octets long.

which points to here (Section 2.3.5):

http://www.secg.org/sec1-v2.pdf

... and that's what JOSE chooses to do, IIRC -- two separate 32 octet uncompressed values for X and Y for P-256.

If we want to use the compressed form, which we probably do, for the base58btc, then @sammotic is correct and it would be 33 bytes in size:

https://stackoverflow.com/questions/6665353/is-there-a-standardized-fixed-length-encoding-for-ec-public-keys

From Section 2.3.2 of the SEC spec, which is the authority on this:

Elliptic curve points should be converted to octet strings as described in this section. Informally, if point compression is being used, the idea is that the compressed y-coordinate is placed in the leftmost octet of the octet string along with an indication that point compression is on, and the x-coordinate is placed in the remainder of the octet string; otherwise if point compression is off, the leftmost octet indicates that point compression is off, and the remainder of the octet string
contains the x-coordinate followed by the y-coordinate.

Follow the algorithm and you get 33 bytes. @selfissued, are you stating that we should do what JOSE does and express it as uncompressed X and Y values? Note that will take 65 bytes if we use the guidance provided by SEC. If we use compressed form per SEC, it will only take 33 bytes.

The intent here was to use compressed form, and so I suggest that @sammotic is correct and we should make the correction to the spec. I will also note that we may not want to say anything in the spec about key values and instead defer to the Linked Data Security specs to make those assertions... that DID Core is getting these details peppered throughout it is the wrong thing to do, IMHO.

Implications for https://github.com/multiformats/multicodec/pull/190

I agree that the linked data specs are the correct place to define these details... we don't have this problem when we use publicKeyJwk, and when I create an agile linked data suite for all Multicodec key representations (smiles an @msporny ;), I could define specifically which format I would support....

When I implemented support for P-384, I handled it this way:

Encoding

https://github.com/transmute-industries/did-key.js/blob/master/packages/p384/src/keyUtils.ts#L32

Fixtures

https://github.com/transmute-industries/did-key.js/blob/master/packages/p384/src/__fixtures__/test-vectors/publicKeyBase58.txt

https://github.com/transmute-industries/did-key.js/blob/master/packages/p384/src/__fixtures__/test-vectors/publicKeyJwk.json

I assume this is "uncompressed" given I didn't do any transformation....

Given the comments, I am removing the pending close tab

This sort of specificity should probably be removed from the specification... feels like we're headed in that direction as a WG.

We should remove this language from the specification and defer to the LD Cryptosuite (JWK or Secp256r1) to define the encoding for the key.

PR #490 addresses this issue by removing the specifics around secp256r1 key formats and deferring the definition of those to the cryptosuites. This issue will be closed once PR #490 is merged.

PR #490 has been merged, closing.

Was this page helpful?
0 / 5 - 0 ratings