Zynk
Getting StartedProduct GuidesAPI ReferenceFAQ'sRecipes
Getting StartedProduct GuidesAPI ReferenceFAQ'sRecipes
  1. Continuum - Wallet Infrastructure
  • Transformer - Cross Border Transfer
    • Overview
    • Customers & Identity
      • Entities/Customers
      • About KYC/KYB
      • RFI Scenarios for Customers
      • Identity Rejection Reasons
    • Accounts & Wallets
      • External Accounts(To be deprecated soon)
      • Fetch Requirements for External Accounts V2
      • External Accounts V2
      • Funding Accounts
      • About Plaid Integration
    • Transfers
      • Counterparty Risk details
      • Addition transfer requirements
      • Transfer in Action
      • Limits and Minimums
      • Fee details
    • Miscellaneous
      • Bank Codes
      • Supported chains and currencies
      • Partner payments signature generation
      • Reserves requirements
      • Partner Payments
      • Status updates - Webhooks
  • Transporter - Automated Liquidity Manager
    • Overview
    • Visibility Protocol
    • Instant liquidity process - How it works
    • Status updates - Webhooks
  • Teleport - Pay-In Accounts
    • Overview
    • About Teleport routes
  • Warp - Pay-Outs
    • Overview
  • Continuum - Wallet Infrastructure
    • Overview
    • Authentication
    • Continuum APIs
    • Transactions on Continuum
    • Details on generating signatures
Getting StartedProduct GuidesAPI ReferenceFAQ'sRecipes
Getting StartedProduct GuidesAPI ReferenceFAQ'sRecipes
  1. Continuum - Wallet Infrastructure

Details on generating signatures

Here we provide detailed technical documentation for the three cryptographic methods used in Continuum:
Signing Payloads Using API Key Pairs
This method uses Elliptic Curve Digital Signature Algorithm (ECDSA) to sign payloads using a private key that corresponds to a registered public key (API key).
Algorithm Details
Supported Curves:
P-256 (secp256r1): Most commonly used
SECP256K1: Used for Ethereum-compatible keys
ED25519: EdDSA signature scheme
For P-256 (Primary Method):
Signature Algorithm: ECDSA (Elliptic Curve Digital Signature Algorithm)
Hash Function: SHA-256
Curve: P-256 (prime256v1, secp256r1)
Key Format:
Private Key: 64-character hexadecimal string (32 bytes)
Public Key: Compressed format, 66-character hexadecimal string (33 bytes: 0x02 or 0x03 prefix + 32-byte x-coordinate)
Key Requirements
Public Key Format: The public key MUST be in compressed format
Signature Construction Process
1
Hash the Payload
2
Sign the Hash
      const ec = new EC('p256');
const key = ec.keyFromPrivate(privateKeyHex, 'hex');
const signature = key.sign(hashHex, { canonical: true });
      
3
Encode Signature to DER Format
const derHex = signature.toDER('hex'); // DER-encoded signature
4
Construct Signature Object
const stampObj = {
 publicKey: compressedPublicKey, // 66-char hex string
 scheme: 'SIGNATURE_SCHEME_TK_API_P256',
 signature: derHex, // DER-encoded signature as hex
};
5
Encode Signature
const signature = base64UrlEncode(JSON.stringify(stampObj));
// Use signature in your API request
Signature Format Details
DER Encoding:
The ECDSA signature is encoded using Distinguished Encoding Rules (DER)
Format: SEQUENCE { r INTEGER, s INTEGER }
The DER-encoded signature is represented as a hexadecimal string
Typical length: 70-72 bytes (140-144 hex characters)
Final Signature Format:
JSON object containing:
publicKey: Compressed public key (66-char hex)
scheme: Signature scheme identifier string
signature: DER-encoded signature (hex string)
Base64URL encoded for HTTP header transmission
ReactJS Function Example

import { ec as EC } from 'elliptic';

// SHA-256 hashing function
const sha256 = async (input) => {
  const data = new TextEncoder().encode(input);
  const hashBuffer = await crypto.subtle.digest('SHA-256', data);
  return Array.from(new Uint8Array(hashBuffer))
    .map((b) => b.toString(16).padStart(2, '0'))
    .join('');
};

// Base64URL encoding
const toBase64Url = (str) => {
  const b64 = btoa(unescape(encodeURIComponent(str)));
  return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
};

/**
 * Sign payload using API key pair
 * @param {string} payload - The payload string to sign (typically JSON.stringify(requestBody))
 * @param {string} apiPrivateKey - 64-character hex string (32 bytes)
 * @param {string} apiPublicKey - 66-character hex string (33 bytes, compressed)
 * @returns {Promise-{signature: string, details: object}-} - Signature result
 */
export const signPayloadWithApiKey = async (payload, apiPrivateKey, apiPublicKey) => {
  if (!apiPrivateKey || !apiPublicKey) {
    throw new Error('API key pair not found');
  }

  // Initialize elliptic curve (P-256)
  const ec = new EC('p256');

  // Verify public key matches private key
  const key = ec.keyFromPrivate(apiPrivateKey, 'hex');
  const derivedPubHex = key.getPublic(true, 'hex'); // Compressed format

  if (derivedPubHex !== apiPublicKey) {
    throw new Error('Public key does not match private key');
  }

  // Hash the payload
  const hashHex = await sha256(payload);

  // Sign the hash
  const sig = key.sign(hashHex, { canonical: true });

  // Encode signature to DER format
  const derHex = sig.toDER('hex');

  // Construct signature object
  const stampObj = {
    publicKey: apiPublicKey,
    scheme: 'SIGNATURE_SCHEME_TK_API_P256',
    signature: derHex,
  };

  // Base64URL encode the signature
  const signature = toBase64Url(JSON.stringify(stampObj));

  return {
    signature,
    details: {
      publicKey: apiPublicKey,
      scheme: stampObj.scheme,
      signature: derHex,
      payloadHash: hashHex,
    },
  };
};

// Usage example:
// const result = await signPayloadWithApiKey(
//   JSON.stringify(requestBody),
//   localStorage.getItem('apiPrivateKey'),
//   localStorage.getItem('apiPublicKey')
// );
// // Use result.signature in your API request
Key points to note:
Public keys MUST be in compressed format (33 bytes = 66 hex chars)
Private keys are 32-byte hex strings (64 hex chars)
Signatures use DER encoding for interoperability
SHA-256 hashing is applied to the payload before signing
Canonical signatures ensure deterministic output
Signing Payloads Using Passkeys (WebAuthn)
Decrypting Credential Bundles Using HPKE
Modified at 2025-11-04 13:35:02
Previous
Transactions on Continuum
Built with