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