Low level bindings for libsodium cryptographic library
—
Low-level elliptic curve operations on Ed25519 for advanced cryptographic protocols, scalar arithmetic, and point operations.
Perform scalar multiplication operations on Ed25519 curve points.
/**
* Multiply Ed25519 base point by scalar
* @param q - Output buffer for resulting point (must be BYTES long)
* @param n - Scalar buffer (must be SCALARBYTES long)
* @throws Error if buffer sizes are incorrect or operation fails
*/
function crypto_scalarmult_ed25519_base(q: Buffer, n: Buffer): void;
/**
* Multiply Ed25519 point by scalar
* @param q - Output buffer for resulting point (must be BYTES long)
* @param n - Scalar buffer (must be SCALARBYTES long)
* @param p - Point buffer to multiply (must be BYTES long)
* @throws Error if buffer sizes are incorrect or operation fails
*/
function crypto_scalarmult_ed25519(q: Buffer, n: Buffer, p: Buffer): void;
/**
* Multiply Ed25519 base point by scalar (no clamping)
* @param q - Output buffer for resulting point (must be BYTES long)
* @param n - Scalar buffer (must be SCALARBYTES long)
* @throws Error if buffer sizes are incorrect or operation fails
*/
function crypto_scalarmult_ed25519_base_noclamp(q: Buffer, n: Buffer): void;
/**
* Multiply Ed25519 point by scalar (no clamping)
* @param q - Output buffer for resulting point (must be BYTES long)
* @param n - Scalar buffer (must be SCALARBYTES long)
* @param p - Point buffer to multiply (must be BYTES long)
* @throws Error if buffer sizes are incorrect or operation fails
*/
function crypto_scalarmult_ed25519_noclamp(q: Buffer, n: Buffer, p: Buffer): void;Usage Example:
const sodium = require('sodium-native');
// Generate random scalar
const scalar = Buffer.alloc(sodium.crypto_scalarmult_ed25519_SCALARBYTES);
sodium.randombytes_buf(scalar);
// Multiply base point by scalar (equivalent to generating public key)
const point = Buffer.alloc(sodium.crypto_scalarmult_ed25519_BYTES);
sodium.crypto_scalarmult_ed25519_base(point, scalar);
// Multiply the resulting point by another scalar
const scalar2 = Buffer.alloc(sodium.crypto_scalarmult_ed25519_SCALARBYTES);
sodium.randombytes_buf(scalar2);
const point2 = Buffer.alloc(sodium.crypto_scalarmult_ed25519_BYTES);
sodium.crypto_scalarmult_ed25519(point2, scalar2, point);Perform addition and subtraction operations on Ed25519 curve points.
/**
* Add two Ed25519 points
* @param r - Output buffer for result point (must be BYTES long)
* @param p - First point buffer (must be BYTES long)
* @param q - Second point buffer (must be BYTES long)
* @throws Error if buffer sizes are incorrect or operation fails
*/
function crypto_core_ed25519_add(r: Buffer, p: Buffer, q: Buffer): void;
/**
* Subtract Ed25519 points (r = p - q)
* @param r - Output buffer for result point (must be BYTES long)
* @param p - First point buffer (must be BYTES long)
* @param q - Second point buffer (must be BYTES long)
* @throws Error if buffer sizes are incorrect or operation fails
*/
function crypto_core_ed25519_sub(r: Buffer, p: Buffer, q: Buffer): void;Check if a buffer represents a valid Ed25519 curve point.
/**
* Check if buffer represents a valid Ed25519 point
* @param p - Point buffer to validate (must be BYTES long)
* @returns true if point is valid, false otherwise
*/
function crypto_core_ed25519_is_valid_point(p: Buffer): boolean;Generate Ed25519 points from uniform random bytes.
/**
* Map uniform bytes to Ed25519 curve point
* @param p - Output buffer for point (must be BYTES long)
* @param r - Uniform random bytes (must be UNIFORMBYTES long)
* @throws Error if buffer sizes are incorrect or mapping fails
*/
function crypto_core_ed25519_from_uniform(p: Buffer, r: Buffer): void;Usage Example:
const sodium = require('sodium-native');
// Generate two random points
const uniform1 = Buffer.alloc(sodium.crypto_core_ed25519_UNIFORMBYTES);
const uniform2 = Buffer.alloc(sodium.crypto_core_ed25519_UNIFORMBYTES);
sodium.randombytes_buf(uniform1);
sodium.randombytes_buf(uniform2);
const point1 = Buffer.alloc(sodium.crypto_core_ed25519_BYTES);
const point2 = Buffer.alloc(sodium.crypto_core_ed25519_BYTES);
sodium.crypto_core_ed25519_from_uniform(point1, uniform1);
sodium.crypto_core_ed25519_from_uniform(point2, uniform2);
// Validate points
console.log('Point 1 valid:', sodium.crypto_core_ed25519_is_valid_point(point1));
console.log('Point 2 valid:', sodium.crypto_core_ed25519_is_valid_point(point2));
// Add points
const sum = Buffer.alloc(sodium.crypto_core_ed25519_BYTES);
sodium.crypto_core_ed25519_add(sum, point1, point2);
// Subtract points
const difference = Buffer.alloc(sodium.crypto_core_ed25519_BYTES);
sodium.crypto_core_ed25519_sub(difference, point1, point2);Perform arithmetic operations on Ed25519 scalars.
/**
* Generate random Ed25519 scalar
* @param r - Output buffer for scalar (must be SCALARBYTES long)
*/
function crypto_core_ed25519_scalar_random(r: Buffer): void;
/**
* Reduce bytes to Ed25519 scalar modulo curve order
* @param r - Output buffer for reduced scalar (must be SCALARBYTES long)
* @param s - Input bytes to reduce (must be NONREDUCEDSCALARBYTES long)
*/
function crypto_core_ed25519_scalar_reduce(r: Buffer, s: Buffer): void;
/**
* Invert Ed25519 scalar (multiplicative inverse)
* @param recip - Output buffer for inverted scalar (must be SCALARBYTES long)
* @param s - Scalar buffer to invert (must be SCALARBYTES long)
*/
function crypto_core_ed25519_scalar_invert(recip: Buffer, s: Buffer): void;
/**
* Negate Ed25519 scalar
* @param neg - Output buffer for negated scalar (must be SCALARBYTES long)
* @param s - Scalar buffer to negate (must be SCALARBYTES long)
*/
function crypto_core_ed25519_scalar_negate(neg: Buffer, s: Buffer): void;
/**
* Complement Ed25519 scalar (1 - s)
* @param comp - Output buffer for complement (must be SCALARBYTES long)
* @param s - Scalar buffer to complement (must be SCALARBYTES long)
*/
function crypto_core_ed25519_scalar_complement(comp: Buffer, s: Buffer): void;
/**
* Add Ed25519 scalars modulo curve order
* @param z - Output buffer for sum (must be SCALARBYTES long)
* @param x - First scalar buffer (must be SCALARBYTES long)
* @param y - Second scalar buffer (must be SCALARBYTES long)
*/
function crypto_core_ed25519_scalar_add(z: Buffer, x: Buffer, y: Buffer): void;
/**
* Subtract Ed25519 scalars modulo curve order
* @param z - Output buffer for difference (must be SCALARBYTES long)
* @param x - First scalar buffer (must be SCALARBYTES long)
* @param y - Second scalar buffer (must be SCALARBYTES long)
*/
function crypto_core_ed25519_scalar_sub(z: Buffer, x: Buffer, y: Buffer): void;Usage Example:
const sodium = require('sodium-native');
// Generate random scalars
const scalar1 = Buffer.alloc(sodium.crypto_core_ed25519_SCALARBYTES);
const scalar2 = Buffer.alloc(sodium.crypto_core_ed25519_SCALARBYTES);
sodium.crypto_core_ed25519_scalar_random(scalar1);
sodium.crypto_core_ed25519_scalar_random(scalar2);
// Scalar arithmetic
const sum = Buffer.alloc(sodium.crypto_core_ed25519_SCALARBYTES);
const difference = Buffer.alloc(sodium.crypto_core_ed25519_SCALARBYTES);
const inverse = Buffer.alloc(sodium.crypto_core_ed25519_SCALARBYTES);
sodium.crypto_core_ed25519_scalar_add(sum, scalar1, scalar2);
sodium.crypto_core_ed25519_scalar_sub(difference, scalar1, scalar2);
sodium.crypto_core_ed25519_scalar_invert(inverse, scalar1);
// Reduce large bytes to scalar
const largeBytes = Buffer.alloc(sodium.crypto_core_ed25519_NONREDUCEDSCALARBYTES);
sodium.randombytes_buf(largeBytes);
const reducedScalar = Buffer.alloc(sodium.crypto_core_ed25519_SCALARBYTES);
sodium.crypto_core_ed25519_scalar_reduce(reducedScalar, largeBytes);Perform scalar multiplication on Curve25519 (Montgomery form).
/**
* Multiply Curve25519 base point by scalar
* @param q - Output buffer for resulting point (must be BYTES long)
* @param n - Scalar buffer (must be SCALARBYTES long)
* @throws Error if buffer sizes are incorrect or operation fails
*/
function crypto_scalarmult_base(q: Buffer, n: Buffer): void;
/**
* Multiply Curve25519 point by scalar
* @param q - Output buffer for resulting point (must be BYTES long)
* @param n - Scalar buffer (must be SCALARBYTES long)
* @param p - Point buffer to multiply (must be BYTES long)
* @throws Error if buffer sizes are incorrect or operation fails
*/
function crypto_scalarmult(q: Buffer, n: Buffer, p: Buffer): void;// Ed25519 point size in bytes
const crypto_core_ed25519_BYTES: number;
// Ed25519 uniform bytes size for point generation
const crypto_core_ed25519_UNIFORMBYTES: number;
// Ed25519 scalar size in bytes
const crypto_core_ed25519_SCALARBYTES: number;
// Ed25519 non-reduced scalar size in bytes
const crypto_core_ed25519_NONREDUCEDSCALARBYTES: number;
// Ed25519 scalar multiplication constants
const crypto_scalarmult_ed25519_BYTES: number;
const crypto_scalarmult_ed25519_SCALARBYTES: number;
// Curve25519 scalar multiplication constants
const crypto_scalarmult_BYTES: number;
const crypto_scalarmult_SCALARBYTES: number;crypto_core_ed25519_is_valid_point for untrusted points.const sodium = require('sodium-native');
class ThresholdSignature {
static generateShares(threshold, participants) {
const coefficients = [];
// Generate polynomial coefficients
for (let i = 0; i < threshold; i++) {
const coeff = Buffer.alloc(sodium.crypto_core_ed25519_SCALARBYTES);
sodium.crypto_core_ed25519_scalar_random(coeff);
coefficients.push(coeff);
}
const shares = [];
// Generate shares for each participant
for (let participant = 1; participant <= participants; participant++) {
let share = Buffer.alloc(sodium.crypto_core_ed25519_SCALARBYTES);
share.fill(0);
// Evaluate polynomial at participant index
for (let i = 0; i < coefficients.length; i++) {
const term = Buffer.alloc(sodium.crypto_core_ed25519_SCALARBYTES);
// term = coefficient * (participant^i)
// Simplified for example - real implementation needs proper field arithmetic
if (i === 0) {
Buffer.from(coefficients[i]).copy(term);
} else {
// Simplified power computation
Buffer.from(coefficients[i]).copy(term);
}
sodium.crypto_core_ed25519_scalar_add(share, share, term);
}
shares.push({ participant, share });
}
return { shares, publicKey: this.derivePublicKey(coefficients[0]) };
}
static derivePublicKey(secretKey) {
const publicKey = Buffer.alloc(sodium.crypto_scalarmult_ed25519_BYTES);
sodium.crypto_scalarmult_ed25519_base(publicKey, secretKey);
return publicKey;
}
}const sodium = require('sodium-native');
class ECDHKeyExchange {
constructor() {
// Generate private key (scalar)
this.privateKey = Buffer.alloc(sodium.crypto_scalarmult_SCALARBYTES);
sodium.randombytes_buf(this.privateKey);
// Generate public key (point)
this.publicKey = Buffer.alloc(sodium.crypto_scalarmult_BYTES);
sodium.crypto_scalarmult_base(this.publicKey, this.privateKey);
}
// Compute shared secret with peer's public key
computeSharedSecret(peerPublicKey) {
const sharedSecret = Buffer.alloc(sodium.crypto_scalarmult_BYTES);
sodium.crypto_scalarmult(sharedSecret, this.privateKey, peerPublicKey);
return sharedSecret;
}
// Derive encryption key from shared secret
deriveKey(sharedSecret, info = 'encryption') {
const key = Buffer.alloc(32);
const combined = Buffer.concat([sharedSecret, Buffer.from(info)]);
sodium.crypto_generichash(key, combined);
return key;
}
}
// Usage
const alice = new ECDHKeyExchange();
const bob = new ECDHKeyExchange();
const aliceShared = alice.computeSharedSecret(bob.publicKey);
const bobShared = bob.computeSharedSecret(alice.publicKey);
console.log('Shared secrets match:', aliceShared.equals(bobShared));
const encryptionKey = alice.deriveKey(aliceShared);const sodium = require('sodium-native');
class PointCompression {
// Compress Ed25519 point (32 bytes -> 32 bytes with sign bit)
static compressPoint(point) {
// Ed25519 points are already in compressed form in sodium-native
// This is a conceptual example
return point;
}
// Decompress Ed25519 point
static decompressPoint(compressedPoint) {
// Validate the compressed point
if (!sodium.crypto_core_ed25519_is_valid_point(compressedPoint)) {
throw new Error('Invalid compressed point');
}
return compressedPoint;
}
// Generate valid random point
static generateRandomPoint() {
const uniform = Buffer.alloc(sodium.crypto_core_ed25519_UNIFORMBYTES);
sodium.randombytes_buf(uniform);
const point = Buffer.alloc(sodium.crypto_core_ed25519_BYTES);
sodium.crypto_core_ed25519_from_uniform(point, uniform);
return point;
}
}const sodium = require('sodium-native');
class MultiScalarMult {
// Compute sum of scalar multiplications: s1*P1 + s2*P2 + ... + sn*Pn
static multiScalarMult(scalars, points) {
if (scalars.length !== points.length) {
throw new Error('Scalars and points arrays must have same length');
}
let result = Buffer.alloc(sodium.crypto_core_ed25519_BYTES);
result.fill(0); // Start with identity point
for (let i = 0; i < scalars.length; i++) {
const product = Buffer.alloc(sodium.crypto_scalarmult_ed25519_BYTES);
sodium.crypto_scalarmult_ed25519(product, scalars[i], points[i]);
if (i === 0) {
Buffer.from(product).copy(result);
} else {
sodium.crypto_core_ed25519_add(result, result, product);
}
}
return result;
}
// Compute linear combination with base point: s1*G + s2*P2 + ... + sn*Pn
static linearCombination(baseScalar, scalars, points) {
const baseProduct = Buffer.alloc(sodium.crypto_scalarmult_ed25519_BYTES);
sodium.crypto_scalarmult_ed25519_base(baseProduct, baseScalar);
if (scalars.length === 0) {
return baseProduct;
}
const otherProducts = this.multiScalarMult(scalars, points);
const result = Buffer.alloc(sodium.crypto_core_ed25519_BYTES);
sodium.crypto_core_ed25519_add(result, baseProduct, otherProducts);
return result;
}
}Install with Tessl CLI
npx tessl i tessl/npm-sodium-native