import * as bn128 from '@aztec/bn128';
import { constants } from '@aztec/dev-utils';
import secp256k1 from '@aztec/secp256k1';
import BN from 'bn.js';
import crypto from 'crypto';
import { padLeft, toHex } from 'web3-utils';
import * as note from '../../src/note';
const mockLightNote = async (k) => {
const a = padLeft(new BN(crypto.randomBytes(32), 16).umod(bn128.curve.n).toString(16), 64);
const kHex = padLeft(toHex(Number(k).toString(10)).slice(2), 8);
const ephemeral = secp256k1.ec.keyFromPrivate(crypto.randomBytes(32));
const viewingKey = `0x${a}${kHex}${padLeft(ephemeral.getPublic(true, 'hex'), 66)}`;
return note.fromViewKey(viewingKey);
};
/**
* Construct a mock note directly from the setup algorithm's trapdoor key.
* Used for testing purposes only; we don't know the trapdoor key for the real deal.
*/
const mockNote = async (k, trapdoor) => {
const lightNote = await mockLightNote(k);
const kBn = new BN(k).toRed(bn128.groupReduction);
const mu = bn128.h.mul(trapdoor.redSub(kBn).redInvm());
const gamma = mu.mul(lightNote.a);
const sigma = gamma.mul(kBn).add(bn128.h.mul(lightNote.a));
return {
...lightNote,
gamma,
sigma,
};
};
/**
* Create a set of mock light notes from vectors of input and output values
*
* @method mockLightNoteSet
* @param {number[]} kIn vector of input note values
* @param {number[]} kOut vector of output note values
* @returns {Object} input notes and output notes
*/
const mockLightNoteSet = async (kIn, kOut) => {
const inputNotes = await Promise.all(
kIn.map((k) => {
return mockLightNote(k);
}),
);
const outputNotes = await Promise.all(
kOut.map((k) => {
return mockLightNote(k);
}),
);
return { inputNotes, outputNotes };
};
/**
* Create a set of mock notes from vectors of input and output values.
* This method uses a randomly generated trapdoor key instead of the trusted setup key.
*
* @method mockNoteSet
* @param {number[]} kIn vector of input note values
* @param {number[]} kOut vector of output note values
* @returns {Object} input notes, output notes and trapdoor function
*/
const mockNoteSet = async (kIn, kOut) => {
const trapdoor = new BN(crypto.randomBytes(32), 16).toRed(bn128.groupReduction);
const inputNotes = await Promise.all(
kIn.map((k) => {
return mockNote(k, trapdoor);
}),
);
const outputNotes = await Promise.all(
kOut.map((k) => {
return mockNote(k, trapdoor);
}),
);
return { inputNotes, outputNotes, trapdoor };
};
function kMaxBoundValue(value) {
if (process.env.NODE_ENV === 'TEST' || process.env.NODE_ENV === 'development') {
return value > constants.K_MAX_TEST ? constants.K_MAX_TEST : value;
}
return value > constants.K_MAX ? constants.K_MAX : value;
}
/**
* Generate a random note value that is less than K_MAX
*
* @method randomNoteValue
* @param {number} maxValue max value of random note
* @returns {BN} - big number instance of an AZTEC note value
*/
const randomNoteValue = (maxValue = constants.K_MAX) => {
return Math.floor(Math.random() * kMaxBoundValue(maxValue));
};
/**
* Generate a set of notes with a defined total value
*
* @method noteSetOfValue
* @param {number} numberOfNotes number of notes
* @param {number} totalValue sum of notes
* @returns {Array} - Array of notes
*/
const noteSetOfValue = (numberOfNotes, totalValue) => {
const averageValue = Math.floor(kMaxBoundValue(totalValue) / numberOfNotes);
const notes = [];
for (let i = 0; i < numberOfNotes; i += 1) {
if (i === numberOfNotes - 1) {
notes[i] = totalValue - averageValue * i;
} else {
notes[i] = averageValue;
}
}
return notes;
};
/**
* Generate a set of random input and output values based on the number of notes.
*
* @param {number} nIn number of input notes
* @param {number} nOut number of output notes
*/
const balancedPublicValues = (nIn, nOut) => {
const transactionAmount = randomNoteValue();
const kIn = noteSetOfValue(nIn, transactionAmount);
const kOut = noteSetOfValue(nOut, transactionAmount);
return { kIn, kOut };
};
/**
* Dummy account used to test the granting of note view access
*/
const userAccount = {
address: '0xfB95acC8D3870da3C646Ae8c3C621916De8DF42d',
linkedPublicKey: '0xa61d17b0dd3095664d264628a6b947721314b6999aa6a73d3c7698f041f78a4d',
linkedPrivateKey: 'e1ec35b90155a633ac75d0508e537a7e00fd908a5295365054001a44b4a0560c',
spendingPublicKey: '0x0290e0354caa04c73920339f979cfc932dd3d52ba8210fec34571bb6422930c396',
};
/**
* Second dummy account used to test the granting of note view access
*/
const userAccount2 = {
address: '0x61EeAd169ec67b24abee7B81Ca750b6dCA3a9CCd',
linkedPublicKey: '0x058d55269a83b5ea379931ac58bc3def375eab12e527708111545af46f5f9b5c',
linkedPrivateKey: '6a30cc7b28b037b47378522a1a370c2394b0dd2d70c6abbe5ac66c8a1d84db21',
spendingPublicKey: '0x02090a6b89b0588626f26babc87f2dc1e2c815b8248754bed93d837f7071411605',
};
export { balancedPublicValues, mockLightNoteSet, mockNoteSet, randomNoteValue, userAccount, userAccount2 };