poseidon: refactor validateOpts, fix tests

This commit is contained in:
Paul Miller 2023-08-21 15:48:34 +00:00
parent 62749382e7
commit ef667bb404
No known key found for this signature in database
GPG Key ID: 697079DA6878B89B
2 changed files with 34 additions and 29 deletions

@ -15,33 +15,36 @@ export type PoseidonOpts = {
};
export function validateOpts(opts: PoseidonOpts) {
const { Fp } = opts;
const { Fp, mds, reversePartialPowIdx: rev, roundConstants: rc } = opts;
const { roundsFull, roundsPartial, sboxPower, t } = opts;
validateField(Fp);
for (const i of ['t', 'roundsFull', 'roundsPartial'] as const) {
if (typeof opts[i] !== 'number' || !Number.isSafeInteger(opts[i]))
throw new Error(`Poseidon: invalid param ${i}=${opts[i]} (${typeof opts[i]})`);
}
const rev = opts.reversePartialPowIdx;
// MDS is TxT matrix
if (!Array.isArray(mds) || mds.length !== t) throw new Error('Poseidon: wrong MDS matrix');
const _mds = mds.map((mdsRow) => {
if (!Array.isArray(mdsRow) || mdsRow.length !== t)
throw new Error(`Poseidon MDS matrix row: ${mdsRow}`);
return mdsRow.map((i) => {
if (typeof i !== 'bigint') throw new Error(`Poseidon MDS matrix value=${i}`);
return Fp.create(i);
});
});
if (rev !== undefined && typeof rev !== 'boolean')
throw new Error(`Poseidon: invalid param reversePartialPowIdx=${rev}`);
let { sboxPower } = opts;
if (!sboxPower || ![3, 5, 7].includes(sboxPower))
throw new Error(`Poseidon wrong sboxPower=${sboxPower}`);
const _sboxPower = BigInt(sboxPower);
let sboxFn = (n: bigint) => FpPow(Fp, n, _sboxPower);
// Unwrapped sbox power for common cases (195->142μs)
if (sboxPower === 3) sboxFn = (n: bigint) => Fp.mul(Fp.sqrN(n), n);
else if (sboxPower === 5) sboxFn = (n: bigint) => Fp.mul(Fp.sqrN(Fp.sqrN(n)), n);
if (roundsFull % 2 !== 0) throw new Error(`Poseidon roundsFull is not even: ${roundsFull}`);
const rounds = roundsFull + roundsPartial;
if (opts.roundsFull % 2 !== 0)
throw new Error(`Poseidon roundsFull is not even: ${opts.roundsFull}`);
const rounds = opts.roundsFull + opts.roundsPartial;
if (!Array.isArray(opts.roundConstants) || opts.roundConstants.length !== rounds)
if (!Array.isArray(rc) || rc.length !== rounds)
throw new Error('Poseidon: wrong round constants');
const roundConstants = opts.roundConstants.map((rc) => {
if (!Array.isArray(rc) || rc.length !== opts.t)
const roundConstants = rc.map((rc) => {
if (!Array.isArray(rc) || rc.length !== t)
throw new Error(`Poseidon wrong round constants: ${rc}`);
return rc.map((i) => {
if (typeof i !== 'bigint' || !Fp.isValid(i))
@ -49,18 +52,16 @@ export function validateOpts(opts: PoseidonOpts) {
return Fp.create(i);
});
});
// MDS is TxT matrix
if (!Array.isArray(opts.mds) || opts.mds.length !== opts.t)
throw new Error('Poseidon: wrong MDS matrix');
const mds = opts.mds.map((mdsRow) => {
if (!Array.isArray(mdsRow) || mdsRow.length !== opts.t)
throw new Error(`Poseidon MDS matrix row: ${mdsRow}`);
return mdsRow.map((i) => {
if (typeof i !== 'bigint') throw new Error(`Poseidon MDS matrix value=${i}`);
return Fp.create(i);
});
});
return Object.freeze({ ...opts, rounds, sboxFn, roundConstants, mds });
if (!sboxPower || ![3, 5, 7].includes(sboxPower))
throw new Error(`Poseidon wrong sboxPower=${sboxPower}`);
const _sboxPower = BigInt(sboxPower);
let sboxFn = (n: bigint) => FpPow(Fp, n, _sboxPower);
// Unwrapped sbox power for common cases (195->142μs)
if (sboxPower === 3) sboxFn = (n: bigint) => Fp.mul(Fp.sqrN(n), n);
else if (sboxPower === 5) sboxFn = (n: bigint) => Fp.mul(Fp.sqrN(Fp.sqrN(n)), n);
return Object.freeze({ ...opts, rounds, sboxFn, roundConstants, mds: _mds });
}
export function splitConstants(rc: bigint[], t: number) {

@ -163,6 +163,7 @@ should('poseidonperm_x5_255_3', () => {
t,
roundsFull: 8,
roundsPartial: 57,
sboxPower: 5,
mds,
roundConstants,
});
@ -229,6 +230,7 @@ should('poseidonperm_x5_255_5', () => {
t,
roundsFull: 8,
roundsPartial: 60,
sboxPower: 5,
mds,
roundConstants,
});
@ -280,6 +282,7 @@ should('poseidonperm_x5_254_3', () => {
t,
roundsFull: 8,
roundsPartial: 57,
sboxPower: 5,
mds,
roundConstants,
});
@ -347,6 +350,7 @@ should('poseidonperm_x5_254_5', () => {
t,
roundsFull: 8,
roundsPartial: 60,
sboxPower: 5,
mds,
roundConstants,
});