Skip to content

Scalar Multiplication

Tony Arcieri edited this page Oct 7, 2013 · 21 revisions

Here be DRAGONS

WARNING: Power-user feature. Not for the faint-at-heart.

RbNaCl provides direct access to the high-speed elliptic curve cryptography available in NaCl (called Curve25519) via the RbNaCl::GroupElement API, which performs scalar multiplication, i.e. adding a point on a Montgomery curve to itself a given number of times. This operation can be done relatively quickly, however the inverse operation, finding a discrete logarithm, is much harder to compute. This asymmetry forms the basis of Curve25519's public key cryptography.

All scalar multiplication operations in NaCl start from a reference base point, the "standard group element". You can obtain this by calling:

RbNaCl::GroupElement.base

There are a few interesting use cases for this API documented below.

Calculating public keys from private keys

Note: this functionality is already provided at a high level using the RbNaCl::PrivateKey#public_key and RbNaCl::SigningKey#verify_key methods.

Unlike systems like RSA where keys must always be stored in keypairs, Curve25519 allows you to store only the private key, and in cases where you would like the corresponding public key, you can use the scalar multiplication API to calculate it for you:

public_key_bytes = RbNaCl::GroupElement.base.mult(private_key_bytes)

Note that every public key in NaCl is an x-coordinate on an elliptic curve, calculated by multiplying the standard group element by your private key (which is treated as an integer)

Diffie-Hellman

Note: this functionality is already provided at a high level using the RbNaCl::Box class. That class also provides a mechanism for exchanging encrypted and authenticated messages.

The scalar multiplication function can be used as part of a Diffie-Hellman key exchange in which a shared secret computed from an exchange of public keys.

For example, Alice and Bob want to set up a shared private secret (e.g. a session key for a cryptographic transport protocol)

Alice and Bob exchange public keys. Alice can now compute a shared secret with:

shared_secret = RbNaCl::GroupElement.new(bob_public_key).mult(alice_private_key)

Bob can likewise compute the same shared secret with:

shared_secret = RbNaCl::GroupElement.new(alice_public_key).mult(bob_private_key)

Together Alice and Bob have now set up a shared secret that can be used for whatever further cryptographic operations they'd like to perform. The shared secret derived from these operations should not be used directly as a key in cryptographic algorithms, but instead be used as the input to a KDF which derives the actual key(s) to be used. NaCl uses this shared secret to derive the symmetric keys for performing XSalsa20 encryption and Poly1305 message authentication when you use RbNaCl::Box.