src/keccak/index.js

import * as bn128 from '@aztec/bn128';
import BN from 'bn.js';
import { keccak256, padLeft } from 'web3-utils';

/**
 * @class
 * @classdesc Class to construct keccak256 hashes required by the AZTEC zero-knowledge proofs
 */
class Keccak {
    constructor() {
        /**
         * array of data being hashed. Each element is a 32-bytes long hex-formatted string
         * @member {string[]}
         */
        this.data = [];
    }

    /**
     * Append a BN.js instance {@link Keccak#data}
     *
     * @method
     * @param {scalar} scalar BN.js number
     */
    appendBN(scalar) {
        this.data.push(padLeft(scalar.toString(16), 64));
    }

    /**
     * Append an elliptic.js group element to {@link Keccak#data}
     *
     * @method
     * @param {Point} point elliptic.js point
     */
    appendPoint(point) {
        this.data.push(padLeft(point.x.fromRed().toString(16), 64));
        this.data.push(padLeft(point.y.fromRed().toString(16), 64));
    }

    /**
     * Compute keccak256 hash of {@link Keccak#data}, set {@link Keccak#data} to resulting hash
     *
     * @method
     * @param {reductionContext} reductionContext BN.js reduction context for Montgomery modular multiplication
     * @returns keccak-ed data
     */
    keccak(reductionContext = null) {
        const paddedData = this.data.map((i) => padLeft(i, 64)).join('');
        this.data = [keccak256(`0x${paddedData}`).slice(2)];
        if (reductionContext) {
            return new BN(this.data[0], 16).toRed(reductionContext);
        }
        return this.data;
    }

    /**
     * Interface for the {@method keccak} with the reduction context set to the constant found in @aztec/dev-utils
     *
     * @method
     * @returns keccak-ed data
     */
    redKeccak() {
        return this.keccak(bn128.groupReduction);
    }
}

export default Keccak;