Skip to content

feat(Ed25519-Key): Improve validation speeds in browsers #3100

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

Chandelier-02
Copy link

@Chandelier-02 Chandelier-02 commented May 12, 2025

Title

feat(Ed25519-Key): Improve validation speeds in browsers

Description

In this PR, I've replaced most Ed25519 key operations with Web Crypto alternatives. With many browsers soon rolling out full support for the Ed25519 key type, this is an opportune time to integrate the new API into Libp2p. The primary benefit is the significant performance improvement that WebCrypto offers.

Simple benchmarks show substantially higher throughput compared to the @noble/curves library implementation of the Ed25519 key.
Screenshot from 2025-05-12 15-12-38

I've also tested the performance difference in one of my projects that receives numerous messages over gossipsub (verified via Ed25519). The results show a dramatic reduction in main thread usage during high message rates, especially with large messages.

Notes & open questions

I could not figure out how to derive a Ed25519 public key from a private key (don't think it's supported in the WebCrypto API), so I am utilizing the Noble Curves library to handle that. Not certain of the security implications of this.

Since Ed25519 key support is currently behind experimental flags in Chromium browsers, I've implemented fallback detection that reverts to the previous Noble curves implementation when the API is unavailable.

There are two tests in the random walk test file that I haven't been able to resolve due to timing conditions: 'should continue random walk until all consumers satisfied' and 'should not block walk on slow consumers'. All other tests are passing.

Change checklist

  • [ x] I have performed a self-review of my own code
  • I have made corresponding changes to the documentation if necessary (this includes comments as well)
  • I have added tests that prove my fix is effective or that my feature works

@Chandelier-02 Chandelier-02 requested a review from a team as a code owner May 12, 2025 20:26
@Chandelier-02 Chandelier-02 changed the title perf(Ed25519-Key): Improve validation speeds in browsers feat(Ed25519-Key): Improve validation speeds in browsers May 12, 2025
@Chandelier-02
Copy link
Author

I have spent some time looking into the reason for why those two specific tests are failing in the 'random-walk.spec.ts' file. The specific test that's failing is this one:

it('should continue random walk until all consumers satisfied', async () => {
    let yielded = 0

    peerRouting.getClosestPeers
      .onFirstCall().callsFake(async function * (key, options?: AbortOptions) {
        for (let i = 0; i < 100; i++) {
          options?.signal?.throwIfAborted()
          yielded++
          yield await createRandomPeerInfo()
        }
      })
      .onSecondCall().returns(slowIterator())

    await Promise.all([
      drain(take(randomWalk.walk(), 1)),
      drain(take(randomWalk.walk(), 2))
    ])

    expect(yielded).to.equal(3)
  })

After adding a bunch of logging in the random-walk file, I do see that each consumer is getting satisfied, but the yield is only occurring twice.

First, PeerInfo-A gets generated, and both consumers see it. The first consumer is then finished as it saw its one peer it wanted. Then, PeerInfo-B gets generated. The second consumer is then finished.

When comparing the old PeerId implementation vs the new one in this PR, the only difference I see that would change test behavior is that the new PR's PeerIds get generated much faster. So, I am thinking there is a race condition in the test. Maybe the test is trying to gauge the wrong metric (number of peer infos yielded vs satisfied consumers).

Maybe I am misunderstanding what this test is trying to do.

Did this change mostly to get the tests in the random-walk.spec to work. However, it is probably also best to not mix and match key generation/derivation functions across libraries. ALl key generation is done via Noble Curves and all signing/verification uses those keys.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant