How to verify Address-Ownership

Certificates

Certificates provide proof of ownership for a specific address. In combination with wallets, they offer a standardized method for signing agreements or creating a sign-in experience with VeChain.

Common use cases include user identification through sign-in and request verification between services.

Anatomy

The structure of a certificate is clearly defined and includes a purpose, payloads, domain, and signer.

interface Certificate {
    /**
     * The purpose field indicates the intended use or context of the certificate.
     * For example, it could be used for identification, verification, or attestation.
     */
    purpose: string;

    /**
     * The payload field holds the actual content of the certificate.
     * This content can be of various types, such as text, images, or other data.
     */
    payload: {
        type: string;
        content: string;
    };

    /**
     * The domain field represents the specific context or domain for which the certificate is valid.
     * It helps ensure that the certificate is only applicable within the intended context.
     */
    domain: string;

    /**
     * The timestamp field records the time at which the certificate was created or issued.
     * This provides a temporal reference for the certificate's validity.
     */
    timestamp: number;

    /**
     * The signer field indicates the address of the entity that signs the certificate.
     * It is the public key address of the entity that issues the certificate.
     */
    signer: string;

    /**
     * The signature field contains the cryptographic signature generated by the issuer's private key.
     * This signature ensures the integrity and authenticity of the certificate's content.
     */
    signature?: string;
}

Sign

To sign a certificate yourself, you will need to:

  1. Obtain the signer's address.

  2. Encode the certificate object into a JSON string. Avoid using JSON.stringify directly, as the key order may vary, potentially causing verification failures across different platforms, use certificate.encode() instead.

  3. Sign the encoded string.

If you possess only the private key, you can derive the public address from its corresponding public key:

// calculate signer from private key
const publicKey = secp256k1.derivePublicKey(privateKey);
cert.signer = addressUtils.fromPublicKey(publicKey);

Signing example:

// encode & sign
const jsonStr = certificate.encode(cert);
const rawSignature = secp256k1.sign(blake2b256(jsonStr), privateKey);
const signature = `0x${rawSignature.toString('hex')}`;

Adding the signature attribute to the certificate turns it into a signed certificate, available for verification on other platforms.

An API verification can consist of a client sending JSON.stringified and base64 encoded version in the headers. The API can then decode and verify the certificate.

Verify

Verification is done using certificate.verify(cert) which will throw in case of any error. Catching errors is therefor important:

try {
  certificate.verify(signedCert);
  console.log('verification successful')
}
catch (err) {
  console.log('verification failed', err.message)  
}

Example Projects

Sign & Verify

Last updated