Skip to content

Ed25519

Preserve standard seed-derived Ed25519 identity while splitting wallet signing authority.

Ed25519 ​

Seams preserves the standard seed-derived Ed25519 identity so an explicitly exported key reproduces the registered public key:

text
d = LE32(y_client + y_server mod 2^256)
h = SHA-512(d)
a = clamp(h[0..32]) mod l

The lifecycle protocol computes this relation through Streaming Yao A/B. Deriver A and Deriver B receive separate client and server contributions. Neither role learns the joined d, a, client signing output, or server signing output.

Lifecycle and signing ​

Registration, recovery, signing-share refresh, SigningWorker activation, authorized export, and new-recipient share provisioning use the lifecycle protocol. Normal transaction, message, and delegate-action signing uses the already-activated threshold session:

text
Client -> Router -> SigningWorker -> Router -> Client

Normal signing performs zero Yao work and makes zero Deriver calls. A presign pool hit takes one client-to-Router request and response. A pool miss uses a prepare request followed by the final signing request.

Export invariant ​

Export is a distinct, freshly authorized ceremony. The client receives two seed shares encrypted to it. It reconstructs d and derives the Ed25519 public key. It must verify that this matches the registered public key before displaying the exported key in the wallet-origin viewer. The app receives only an export outcome.

Ordinary activation circuits have no seed-output branch. Recovery cannot reuse the export request shape.

Sign a NEAR transaction ​

Application code supplies the exact wallet session, NEAR account, receiver, and actions. The SDK routes the request through the active Ed25519 signing lane.

Runnable React and TypeScript example
tsx
import {
  functionCall,
  logWalletEvents,
  TxExecutionStatus,
  useSeams,
  type BoundNearSigner,
} from '@seams/wallet/react';

async function signGreeting(near: BoundNearSigner): Promise<void> {
  await near.signAndSendTransaction({
    receiverId: 'guest-book.testnet',
    actions: [functionCall({ method: 'set_greeting', args: { greeting: 'Hello from Seams' } })],
    options: {
      waitUntil: TxExecutionStatus.EXECUTED_OPTIMISTIC,
      onEvent: logWalletEvents(),
    },
  });
}

export function SetGreetingButton() {
  const { wallet } = useSeams();
  if (wallet?.access !== 'wallet' || !wallet.near) return null;

  // Each request opens wallet confirmation for this transaction.
  return <button onClick={signGreeting.bind(null, wallet.near)}>Sign transaction</button>;
}