CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-tweetnacl

Port of TweetNaCl cryptographic library to JavaScript providing comprehensive cryptographic primitives

Pending
Overview
Eval results
Files

scalarmult.mddocs/

Scalar Multiplication

Low-level scalar multiplication using x25519. These functions provide the underlying elliptic curve operations used by the higher-level box functions, enabling custom cryptographic protocols and key derivation.

Capabilities

Scalar Multiplication Operations

Perform elliptic curve scalar multiplication operations.

/**
 * Multiplies an integer scalar by a group element (point on the curve)
 * @param {Uint8Array} n - The scalar (32 bytes)
 * @param {Uint8Array} p - The group element/point (32 bytes)
 * @returns {Uint8Array} Resulting group element (32 bytes)
 */
nacl.scalarMult(n, p): Uint8Array

/**
 * Multiplies an integer scalar by the standard base point of the curve
 * @param {Uint8Array} n - The scalar (32 bytes) 
 * @returns {Uint8Array} Resulting group element (32 bytes)
 */
nacl.scalarMult.base(n): Uint8Array

Usage Examples:

const nacl = require('tweetnacl');

// Generate a random scalar (private key)
const scalar = nacl.randomBytes(nacl.scalarMult.scalarLength);

// Multiply scalar by base point to get public key
const publicKey = nacl.scalarMult.base(scalar);
console.log(publicKey.length); // 32

// Perform Diffie-Hellman key exchange
const aliceSecret = nacl.randomBytes(32);
const bobSecret = nacl.randomBytes(32);

const alicePublic = nacl.scalarMult.base(aliceSecret);
const bobPublic = nacl.scalarMult.base(bobSecret);

// Both parties can compute the same shared secret
const aliceShared = nacl.scalarMult(aliceSecret, bobPublic);
const bobShared = nacl.scalarMult(bobSecret, alicePublic);

// Verify shared secrets are identical
const secretsMatch = aliceShared.every((byte, i) => byte === bobShared[i]);
console.log(secretsMatch); // true

Key Derivation Example:

const nacl = require('tweetnacl');

// Master key derivation
const masterKey = nacl.randomBytes(32);
const basePoint = nacl.scalarMult.base(masterKey);

// Derive child keys using different scalars
const childScalar1 = nacl.hash(new TextEncoder().encode("child1")).slice(0, 32);
const childScalar2 = nacl.hash(new TextEncoder().encode("child2")).slice(0, 32);

const childKey1 = nacl.scalarMult(childScalar1, basePoint);
const childKey2 = nacl.scalarMult(childScalar2, basePoint);

console.log("Child key 1:", childKey1);
console.log("Child key 2:", childKey2);

Constants

nacl.scalarMult.scalarLength: number        // 32 - Length of scalar in bytes
nacl.scalarMult.groupElementLength: number  // 32 - Length of group element in bytes

Advanced Usage

Custom Diffie-Hellman Implementation

const nacl = require('tweetnacl');

function createDiffieHellmanKeyPair() {
  const secretKey = nacl.randomBytes(nacl.scalarMult.scalarLength);
  const publicKey = nacl.scalarMult.base(secretKey);
  return { secretKey, publicKey };
}

function computeSharedSecret(mySecretKey, theirPublicKey) {
  return nacl.scalarMult(mySecretKey, theirPublicKey);
}

// Usage
const alice = createDiffieHellmanKeyPair();
const bob = createDiffieHellmanKeyPair();

const sharedSecretAlice = computeSharedSecret(alice.secretKey, bob.publicKey);
const sharedSecretBob = computeSharedSecret(bob.secretKey, alice.publicKey);

// Both shared secrets are identical
console.log(sharedSecretAlice.every((byte, i) => byte === sharedSecretBob[i])); // true

Key Validation

const nacl = require('tweetnacl');

function isValidGroupElement(element) {
  if (element.length !== nacl.scalarMult.groupElementLength) {
    return false;
  }
  
  // Check if all bytes are zero (invalid point)
  const allZero = element.every(byte => byte === 0);
  return !allZero;
}

function isValidScalar(scalar) {
  if (scalar.length !== nacl.scalarMult.scalarLength) {
    return false;
  }
  
  // Check if all bytes are zero (invalid scalar)
  const allZero = scalar.every(byte => byte === 0);
  return !allZero;
}

// Example validation
const publicKey = nacl.scalarMult.base(nacl.randomBytes(32));
console.log(isValidGroupElement(publicKey)); // true

const zeroKey = new Uint8Array(32); // All zeros
console.log(isValidGroupElement(zeroKey)); // false

Security Considerations

  • Scalar Validation: Ensure scalars are not all zeros and are properly random when used as private keys.
  • Point Validation: Group elements should be validated to ensure they represent valid curve points.
  • Side-Channel Resistance: The scalar multiplication is designed to be constant-time to prevent timing attacks.
  • Key Management: When using these functions to implement custom protocols, follow proper key management practices.
  • Protocol Design: These are low-level primitives. Most applications should use the higher-level nacl.box functions instead.

Relationship to Box Functions

The nacl.box functions internally use scalar multiplication:

  • nacl.box.keyPair() uses nacl.scalarMult.base() to generate public keys
  • nacl.box.before() uses nacl.scalarMult() to compute shared secrets

Understanding scalar multiplication helps in designing custom protocols or optimizing performance-critical applications.

Install with Tessl CLI

npx tessl i tessl/npm-tweetnacl

docs

box.md

index.md

lowlevel.md

scalarmult.md

secretbox.md

sign.md

utilities.md

tile.json