Cryptographic Signatures

Alice wishes to share a document so that it can be reliably attributed to her, much like the signature on a physical document. This calls for cryptographic signatures, which imbues a document with authentication (we know who signed it), non-repudiation (they can’t later pretend they didn’t sign it), and integrity (we know the document hasn’t been changed since it was signed).

Alice begins by importing Panda-Confidential and instantiating the API.

import {confidential} from "panda-confidential"

{SignatureKeyPair, Message, Declaration, sign, verify} = confidential()

Obtaining A Signing Key Pair

Alice will use a signing key pair to sign the document.

Case 1: Pre-Existing Key Pair

If Alice already has a signature key pair, she may retrieve and deserialize it with the SignatureKeyPair static method from.

alice = SignatureKeyPair.from "base64", serializedKeyPair

Warning: Signature key pairs should be stored securely because they contain private keys.

Case 2: New Key Pair

If Alice wants a new key, she can use the static method create.This provides a key-pair suitable for signing (but not for encryption, which requires an EncryptionKeyPair).

TweetNaCl.js ensures that Alice’s key is random, providing robust randomness regardless of platform. On some platforms, that’s an asynchronous operation, so Confidential returns a promise to provide a consistent interface.

Alice uses await to wait for the promise to resolve.

alice = await SignatureKeyPair.create()

Signing

Alice prepares a Message container for the data she wants to sign. She can use the static method from, which works the same way as it does for SignatureKeyPair.

plaintext = Message.from "utf8", "My name is Alice."

Alice may now sign the data, using her signing key. The sign function returns an instance of [Declaration], which includes the original message, the signatories to that message (their public keys), and the signatures generated by their respective private keys.

declaration = sign alice, plaintext

Under the hood, Panda-Confidential is uses the TweetNaCl.js implementation of digital signing.

Warning: Even though we’re using an instance of Message, sign does not encrypt the data.

Serializing

Alice uses the to method of the Declaration to serialize the declaration so she can share it more easily.

string = declaration.to "base64"

Deserializing

Bob wants to verify the declaration Alice has shared. He uses the from static method of Declaration.

declaration = Declaration.from "base64", serialized

Verifying Signatures

Everything needed for verification is contained within an instance of Declaration, so Bob just passes it to verify. verify returns the boolean result of the verification. If there is more than one signature, all must verify successful for the result to be true.

assert verify declaration

Although Bob can use verify to confirm the self-consistency of the Declaration, Bob can also check to make sure that Alice’s public signing key was, in fact, used to sign the declaration.

assert verify declaration, isSignedWith: alice.publicKey

Adding Signatures

Bob can also sign this Declaration. He just passes the Declaration instance to sign again with his signing key pair. The relevant data will be appended to the signatories and signatures fields within the Declaration instance. If bob references a signing key pair, obtained the same way Alice obtained hers, the code would look like this:

newDeclaration = sign bob, declaration