notes.dt.in.th

Ed25519 keypairs are much more compact than RSA keypair. This note is about how to use them in Node.js.

When used for JWT:

  • The public key is much shorter.
  • The signature is much shorter.
  • The private key is MUCH shorter. See comparison below.

Size comparison

Token size

  • An empty EdDSA-signed JWT with Ed25519 key:

    eyJhbGciOiJFZERTQSIsImtpZCI6IkM5bXBjRHdkUlRtdXRsUkp0UERzNGRQZzI1
    NnRUTUNrSmhlc0IwcDB0Q28ifQ.e30.BppT7qDN4D-NZLpCH255tdwcfQ2rl7PK6
    dTOUUM_NwBjBiu_kVPXZx2jNiXLoLPDS0zDUBYnEkPDMM40WE46DA
    
  • An empty RS256-signed JWT:

    eyJhbGciOiJSUzI1NiIsImtpZCI6IkY3MExCNkM5SnVfUnh2b0ZFMW5lMjZYaGpT
    WEJTdXhmbXpMZ0pzRmRIQnMifQ.e30.XCMc93YPIywzmYzngQPeJ-ROBW8ZNoCJD
    ATV9NuIWE3fn7958PS9glpa-7g2_7bPMKloYneA9joE30f6wE7JbWJ7cs1IzZ7Su
    BY5wFG8rmEaM4Kj9t4MFlnJLwCCk73aj0fuOBiDtLFTAYak37LHpRyI3NOAYWlM7
    DKJ0hfE_QEYhtjtYNE7qqKKpgnOci9tBTz6k0bFHHyAdHUEFScrapaPYqRJIxfnR
    vWg2BMcLIdzfJ2W01QlAdjrs35qjlQHsySoxmI25u5zplTQE_pgjrxUVon9_y_4S
    ahPr2lyT9_Z7M77yHUTqrI1RHi7iqc3SKZOwUygliJB-z9QzyiQAFAQNxejGuKe8
    ts5ZGmFriW2BBFkOVbX1kwowuTYZf2pWrPx_GFBmSW6zYs23_e6nvJyU4MDYLX6L
    5fVZR1jepzYao6VsHKrLbaURbjhGdwhIS0R8SQ1zE5wEgB_T0W9W2iMz_8r2nLbv
    NM2qpi2vikR30thGprZc_JZlwbahbTD42PtKSmD77aW-TuU6dAHR6_UlP3kzdN0h
    ki06QAx8lSpbQ2eJUuPSXH0W1pcI9vW51SuK7gkPA-wS_J6GNzoAZDBzt52Vh7Qy
    Uw78Q_D3mHlGCni9N73ip7W1IXfcHLXtdJazNplUXgS2O5ZkXxR301Yz7ZSSywZg
    bKGVVkbGM0
    

Private key

  • An Ed25519 private key looks like this:

    -----BEGIN PRIVATE KEY-----
    MC4CAQAwBQYDK2VwBCIEIMpf3WUVbXkycxsaLW0NAT8BhVr5nrq7KNlP7LFE9yY4
    -----END PRIVATE KEY-----
    
  • A 4096-bit RSA private key looks like this:

    -----BEGIN RSA PRIVATE KEY-----
    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
    -----END RSA PRIVATE KEY-----
    

Keypair generation

Library support

As of October 2020, despite Ed25519 is supported in OpenSSH for over 5 years, the jsonwebtoken npm package still does not support EdDSA. But jose does.

Sign

jose.JWT.sign(
  {},
  `-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIMpf3WUVbXkycxsaLW0NAT8BhVr5nrq7KNlP7LFE9yY4
-----END PRIVATE KEY-----`,
  { algorithm: 'EdDSA', iat: false }
)

Note: I left out the iat to show that the signature is deterministic.

Verify

jose.JWT.verify(
  'eyJhbGciOiJFZERTQSIsImtpZCI6IkM5bXBjRHdkUlRtdXRsUkp0UERzNGRQZzI1NnRUTUNrSmhlc0IwcDB0Q28ifQ.e30.BppT7qDN4D-NZLpCH255tdwcfQ2rl7PK6dTOUUM_NwBjBiu_kVPXZx2jNiXLoLPDS0zDUBYnEkPDMM40WE46DA',
  `-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEAdFWUonh9OY2IGXUAJoYpuNiIKvEsh93XfvkkXFL6AkA=
-----END PUBLIC KEY-----`,
  { algorithms: ['EdDSA'] }
)