src/note/utils.js

/**
 * Note utility functions
 *
 * @module module:note.utils
 */

import secp256k1 from '@aztec/secp256k1';

import crypto from 'crypto';
import { keccak256, padLeft } from 'web3-utils';

const utils = {};

utils.constants = {
    ZERO_VALUE_NOTE_VIEWING_KEY:
        // eslint-disable-next-line max-len
        '0x00000000000000000000000000000000000000000000000000000000000000010000000002eff9beac9595f45cf86e1d9864f1d3d9460b77a74cb6fbcbd796fd877ef34b34',
};

utils.customMetaData =
    // eslint-disable-next-line max-len
    '0x00000000000000000000000000000028000000000000000000000000000001a4000000000000000000000000000000003339c3c842732f4daacf12aed335661cf4eab66b9db634426a9b63244634d33a2590f06a5ede877e0f2c671075b1aa828a31cbae7462c581c5080390c96159d5c55fdee69634a22c7b9c6d5bc5aad15459282d9277bbd68a88b19857523657a958e1425ff7f315bbe373d3287805ed2a597c3ffab3e8767f9534d8637e793844c13b8c20a574c60e9c4831942b031d2b11a5af633f36615e7a27e4cacdbc7d52fe07056db87e8b545f45b79dac1585288421cc40c8387a65afc5b0e7f2b95a68b3f106d1b76e9fcb5a42d339e031e77d0e767467b5aa2496ee8f3267cbb823168215852aa4ef';

/**
 * Create a Diffie-Hellman shared secret for a given public key
 *
 * @method createSharedSecret
 * @private
 * @param {Object} pubicKeyHex elliptic.js hex-formatted public key
 * @return {{type: string, name: ephemeralKey}} elliptic.js hex-formatted ephemeral key
 * @return {{type: string, name: encoded}} hex-string formatted shared secret
 */
utils.createSharedSecret = (publicKeyHex) => {
    const publicKey = secp256k1.ec.keyFromPublic(publicKeyHex.slice(2), 'hex');
    // When on the web crypto comes from a dependency which acts as a wrapper for browser-level entropy.
    // The version should be fixed to make sure randomness is maintained.
    const ephemeralKey = secp256k1.ec.keyFromPrivate(crypto.randomBytes(32));
    const sharedSecret = publicKey.getPublic().mul(ephemeralKey.priv);
    const sharedSecretHex = `0x${sharedSecret.encode(false).toString('hex')}`;
    const encoded = keccak256(sharedSecretHex, 'hex');
    return {
        ephemeralKey: `0x${ephemeralKey.getPublic(true, 'hex')}`,
        encoded,
    };
};

/**
 * Get the hash of a note's coordinates. Used as identifier in note registry
 *
 * @method getNoteHash
 * @private
 * @param {Object} gamma AZTEC commitment base point
 * @param {Object} sigma AZTEC commitment signed point
 * @returns {string} keccak256 hash in hex-string format
 */
utils.getNoteHash = (gamma, sigma) => {
    const noteType = padLeft('1', 64);
    const gammaX = padLeft(gamma.x.fromRed().toString(16), 64);
    const gammaY = padLeft(gamma.y.fromRed().toString(16), 64);
    const sigmaX = padLeft(sigma.x.fromRed().toString(16), 64);
    const sigmaY = padLeft(sigma.y.fromRed().toString(16), 64);
    return keccak256(`0x${noteType}${gammaX}${gammaY}${sigmaX}${sigmaY}`, 'hex');
};

/**
 * Compute a Diffie-Hellman shared secret between an ephemeral point and a private key
 *
 * @method getSharedSecret
 * @private
 * @param {Object} ephemeralPoint secp256k1 point
 * @param {Object} privateKey hex-string formatted private key
 * @returns {string} hex-string formatted shared secret
 */
utils.getSharedSecret = (ephemeralPoint, privateKey) => {
    const sharedSecret = ephemeralPoint.mul(Buffer.from(privateKey.slice(2), 'hex'));
    const sharedSecretHex = `0x${sharedSecret.encode(false).toString('hex')}`;
    return keccak256(sharedSecretHex, 'hex');
};

utils.randomCustomMetaData = () => {
    const integer = Math.floor(Math.random() * 10);

    const arrayMetaData = utils.customMetaData.split('');
    arrayMetaData[30] = integer;
    return arrayMetaData.join('');
};

export default utils;