mirror of
https://github.com/trezor/trezor-suite.git
synced 2026-03-03 05:55:03 +01:00
chore: allow passing of the source of randomness for arrayShuffle
This commit is contained in:
committed by
Peter Sanderson
parent
4f66613553
commit
e1fe4b85d4
@@ -1,4 +1,4 @@
|
||||
import { scheduleAction, arrayShuffle, urlToOnion } from '@trezor/utils';
|
||||
import { scheduleAction, arrayShuffle, urlToOnion, getWeakRandomInt } from '@trezor/utils';
|
||||
import { TypedEmitter } from '@trezor/utils';
|
||||
import type { BlockbookAPI } from '@trezor/blockchain-link/src/workers/blockbook/websocket';
|
||||
|
||||
@@ -38,7 +38,7 @@ export class CoinjoinBackendClient {
|
||||
|
||||
constructor(settings: CoinjoinBackendClientSettings) {
|
||||
this.logger = settings.logger;
|
||||
this.blockbookUrls = arrayShuffle(settings.blockbookUrls);
|
||||
this.blockbookUrls = arrayShuffle(settings.blockbookUrls, { randomInt: getWeakRandomInt });
|
||||
this.onionDomains = settings.onionDomains ?? {};
|
||||
this.blockbookRequestId = Math.floor(Math.random() * settings.blockbookUrls.length);
|
||||
this.websockets = new CoinjoinWebsocketController(settings);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getWeakRandomId, arrayShuffle } from '@trezor/utils';
|
||||
import { getWeakRandomId, arrayShuffle, getWeakRandomInt } from '@trezor/utils';
|
||||
|
||||
import * as coordinator from '../coordinator';
|
||||
import * as middleware from '../middleware';
|
||||
@@ -160,7 +160,7 @@ export const outputRegistration = async (
|
||||
const assignedAddresses: AccountAddress[] = [];
|
||||
|
||||
return Promise.all(
|
||||
arrayShuffle(outputs).map(output =>
|
||||
arrayShuffle(outputs, { randomInt: getWeakRandomInt }).map(output =>
|
||||
registerOutput(round, account, output, assignedAddresses, options),
|
||||
),
|
||||
);
|
||||
@@ -170,7 +170,9 @@ export const outputRegistration = async (
|
||||
round.setSessionPhase(SessionPhase.AwaitingOthersOutputs);
|
||||
// inform coordinator that each registered input is ready to sign
|
||||
await Promise.all(
|
||||
arrayShuffle(round.inputs).map(input => readyToSign(round, input, options)),
|
||||
arrayShuffle(round.inputs, { randomInt: getWeakRandomInt }).map(input =>
|
||||
readyToSign(round, input, options),
|
||||
),
|
||||
);
|
||||
logger.info(`Ready to sign ~~${round.id}~~`);
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { arrayShuffle } from '@trezor/utils';
|
||||
import { arrayShuffle, getWeakRandomInt } from '@trezor/utils';
|
||||
|
||||
import * as coordinator from '../coordinator';
|
||||
import * as middleware from '../middleware';
|
||||
@@ -234,7 +234,7 @@ export const transactionSigning = async (
|
||||
|
||||
round.setSessionPhase(SessionPhase.SendingSignature);
|
||||
await Promise.all(
|
||||
arrayShuffle(round.inputs).map(input =>
|
||||
arrayShuffle(round.inputs, { randomInt: getWeakRandomInt }).map(input =>
|
||||
sendTxSignature(round, resolvedTime, input, options),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -12,7 +12,7 @@ jest.mock('@trezor/utils', () => {
|
||||
return {
|
||||
__esModule: true,
|
||||
...originalModule,
|
||||
getRandomNumberInRange: () => 0,
|
||||
getWeakRandomNumberInRange: () => 0,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ jest.mock('@trezor/utils', () => {
|
||||
return {
|
||||
__esModule: true,
|
||||
...originalModule,
|
||||
getRandomNumberInRange: () => 0,
|
||||
getWeakRandomNumberInRange: () => 0,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ jest.mock('@trezor/utils', () => {
|
||||
return {
|
||||
__esModule: true,
|
||||
...originalModule,
|
||||
getRandomNumberInRange: () => 0,
|
||||
getWeakRandomNumberInRange: () => 0,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ jest.mock('@trezor/utils', () => {
|
||||
return {
|
||||
__esModule: true,
|
||||
...originalModule,
|
||||
getRandomNumberInRange: () => 0,
|
||||
getWeakRandomNumberInRange: () => 0,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ jest.mock('@trezor/utils', () => {
|
||||
return {
|
||||
__esModule: true,
|
||||
...originalModule,
|
||||
getRandomNumberInRange: jest.fn(() => 0),
|
||||
getWeakRandomNumberInRange: jest.fn(() => 0),
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ jest.mock('@trezor/utils', () => {
|
||||
return {
|
||||
__esModule: true,
|
||||
...originalModule,
|
||||
getRandomNumberInRange: jest.fn(originalModule.getRandomNumberInRange),
|
||||
getWeakRandomNumberInRange: jest.fn(originalModule.getWeakRandomNumberInRange),
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -5,10 +5,14 @@
|
||||
*
|
||||
* This method does not mutate the original array.
|
||||
*/
|
||||
export const arrayShuffle = <T>(array: readonly T[]): T[] => {
|
||||
export const arrayShuffle = <T>(
|
||||
array: readonly T[],
|
||||
{ randomInt }: { randomInt: (min: number, max: number) => number },
|
||||
): T[] => {
|
||||
const shuffled = array.slice();
|
||||
for (let i = shuffled.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
const j = randomInt(0, i + 1);
|
||||
|
||||
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
|
||||
}
|
||||
|
||||
|
||||
13
packages/utils/src/getWeakRandomInt.ts
Normal file
13
packages/utils/src/getWeakRandomInt.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @param min Inclusive
|
||||
* @param max Exclusive
|
||||
*/
|
||||
export const getWeakRandomInt = (min: number, max: number) => {
|
||||
if (min >= max) {
|
||||
throw new RangeError(
|
||||
`The value of "max" is out of range. It must be greater than the value of "min" (${min}). Received ${max}`,
|
||||
);
|
||||
}
|
||||
|
||||
return Math.floor(Math.random() * (max - min) + min);
|
||||
};
|
||||
@@ -1,2 +1,8 @@
|
||||
/**
|
||||
* @deprecated Use `getWeakRandomInt` instead.
|
||||
*
|
||||
* @param min Inclusive
|
||||
* @param max Inclusive
|
||||
*/
|
||||
export const getWeakRandomNumberInRange = (min: number, max: number) =>
|
||||
Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
|
||||
@@ -22,6 +22,7 @@ export * from './getNumberFromPixelString';
|
||||
export * from './getWeakRandomNumberInRange';
|
||||
export * from './getSynchronize';
|
||||
export * from './getWeakRandomId';
|
||||
export * from './getWeakRandomInt';
|
||||
export * from './hasUppercaseLetter';
|
||||
export * from './isAscii';
|
||||
export * from './isHex';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { arrayShuffle } from '../src/arrayShuffle';
|
||||
import { getWeakRandomInt } from '../src/getWeakRandomInt';
|
||||
|
||||
const KEYS = ['a', 'b', 'c', 'd', 'e'];
|
||||
const SAMPLES = 10000;
|
||||
@@ -13,7 +14,7 @@ describe(arrayShuffle.name, () => {
|
||||
const samples = Object.fromEntries(KEYS.map(key => [key, new Array(KEYS.length).fill(0)]));
|
||||
|
||||
for (let sample = 0; sample < SAMPLES; ++sample) {
|
||||
const shuffled = arrayShuffle(KEYS);
|
||||
const shuffled = arrayShuffle(KEYS, { randomInt: getWeakRandomInt });
|
||||
for (let i = 0; i < shuffled.length; ++i) {
|
||||
samples[shuffled[i]][i]++;
|
||||
}
|
||||
|
||||
26
packages/utils/tests/getWeakRandomInt.test.ts
Normal file
26
packages/utils/tests/getWeakRandomInt.test.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { getWeakRandomInt } from '../src';
|
||||
|
||||
describe(getWeakRandomInt.name, () => {
|
||||
it('raises same error as randomInt from crypto when max <= min', () => {
|
||||
const EXPECTED_ERROR = new RangeError(
|
||||
'The value of "max" is out of range. It must be greater than the value of "min" (0). Received -1',
|
||||
);
|
||||
|
||||
expect(() => getWeakRandomInt(0, -1)).toThrowError(EXPECTED_ERROR);
|
||||
});
|
||||
|
||||
it('returns same value when range is trivial', () => {
|
||||
expect(getWeakRandomInt(0, 1)).toEqual(0);
|
||||
expect(getWeakRandomInt(100, 101)).toEqual(100);
|
||||
});
|
||||
|
||||
it('returns same value when range is trivial', () => {
|
||||
for (let i = 0; i < 10_000; i++) {
|
||||
const result = getWeakRandomInt(0, 100);
|
||||
|
||||
expect(Number.isInteger(result)).toBe(true);
|
||||
expect(result).toBeGreaterThanOrEqual(0);
|
||||
expect(result).toBeLessThan(100);
|
||||
}
|
||||
});
|
||||
});
|
||||
11
packages/utils/tests/getWeakRandomNumberInRange.test.ts
Normal file
11
packages/utils/tests/getWeakRandomNumberInRange.test.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { getWeakRandomNumberInRange } from '../src';
|
||||
|
||||
describe(getWeakRandomNumberInRange.name, () => {
|
||||
it('returns value in range', () => {
|
||||
for (let i = 0; i < 10_000; i++) {
|
||||
const result = getWeakRandomNumberInRange(0, 100);
|
||||
expect(result).toBeGreaterThanOrEqual(0);
|
||||
expect(result).toBeLessThanOrEqual(100);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user