utils, hash-to-curve: reduce code duplication

This commit is contained in:
Paul Miller 2024-02-27 22:24:15 +00:00
parent 6a85252dc3
commit 0ce103bd6b
No known key found for this signature in database
GPG Key ID: 697079DA6878B89B
2 changed files with 14 additions and 12 deletions

@ -2,7 +2,7 @@
import type { Group, GroupConstructor, AffinePoint } from './curve.js'; import type { Group, GroupConstructor, AffinePoint } from './curve.js';
import { mod, IField } from './modular.js'; import { mod, IField } from './modular.js';
import type { CHash } from './utils.js'; import type { CHash } from './utils.js';
import { bytesToNumberBE, isBytes, concatBytes, utf8ToBytes, validateObject } from './utils.js'; import { bytesToNumberBE, abytes, isBytes, concatBytes, utf8ToBytes, validateObject } from './utils.js';
/** /**
* * `DST` is a domain separation tag, defined in section 2.2.5 * * `DST` is a domain separation tag, defined in section 2.2.5
@ -52,10 +52,8 @@ function strxor(a: Uint8Array, b: Uint8Array): Uint8Array {
return arr; return arr;
} }
function abytes(item: unknown): void {
if (!isBytes(item)) throw new Error('Uint8Array expected'); function anum(item: unknown): void {
}
function isNum(item: unknown): void {
if (!Number.isSafeInteger(item)) throw new Error('number expected'); if (!Number.isSafeInteger(item)) throw new Error('number expected');
} }
@ -69,7 +67,7 @@ export function expand_message_xmd(
): Uint8Array { ): Uint8Array {
abytes(msg); abytes(msg);
abytes(DST); abytes(DST);
isNum(lenInBytes); anum(lenInBytes);
// https://www.rfc-editor.org/rfc/rfc9380#section-5.3.3 // https://www.rfc-editor.org/rfc/rfc9380#section-5.3.3
if (DST.length > 255) DST = H(concatBytes(utf8ToBytes('H2C-OVERSIZE-DST-'), DST)); if (DST.length > 255) DST = H(concatBytes(utf8ToBytes('H2C-OVERSIZE-DST-'), DST));
const { outputLen: b_in_bytes, blockLen: r_in_bytes } = H; const { outputLen: b_in_bytes, blockLen: r_in_bytes } = H;
@ -103,7 +101,7 @@ export function expand_message_xof(
): Uint8Array { ): Uint8Array {
abytes(msg); abytes(msg);
abytes(DST); abytes(DST);
isNum(lenInBytes); anum(lenInBytes);
// https://www.rfc-editor.org/rfc/rfc9380#section-5.3.3 // https://www.rfc-editor.org/rfc/rfc9380#section-5.3.3
// DST = H('H2C-OVERSIZE-DST-' || a_very_long_DST, Math.ceil((lenInBytes * k) / 8)); // DST = H('H2C-OVERSIZE-DST-' || a_very_long_DST, Math.ceil((lenInBytes * k) / 8));
if (DST.length > 255) { if (DST.length > 255) {
@ -141,7 +139,7 @@ export function hash_to_field(msg: Uint8Array, count: number, options: Opts): bi
}); });
const { p, k, m, hash, expand, DST: _DST } = options; const { p, k, m, hash, expand, DST: _DST } = options;
abytes(msg); abytes(msg);
isNum(count); anum(count);
const DST = validateDST(_DST); const DST = validateDST(_DST);
const log2p = p.toString(2).length; const log2p = p.toString(2).length;
const L = Math.ceil((log2p + k) / 8); // section 5.1 of ietf draft link above const L = Math.ceil((log2p + k) / 8); // section 5.1 of ietf draft link above

@ -23,6 +23,10 @@ export function isBytes(a: unknown): a is Uint8Array {
); );
} }
export function abytes(item: unknown): void {
if (!isBytes(item)) throw new Error('Uint8Array expected');
}
// Array where index 0xf0 (240) is mapped to string 'f0' // Array where index 0xf0 (240) is mapped to string 'f0'
const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) =>
i.toString(16).padStart(2, '0') i.toString(16).padStart(2, '0')
@ -31,7 +35,7 @@ const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) =>
* @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123' * @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
*/ */
export function bytesToHex(bytes: Uint8Array): string { export function bytesToHex(bytes: Uint8Array): string {
if (!isBytes(bytes)) throw new Error('Uint8Array expected'); abytes(bytes);
// pre-caching improves the speed 6x // pre-caching improves the speed 6x
let hex = ''; let hex = '';
for (let i = 0; i < bytes.length; i++) { for (let i = 0; i < bytes.length; i++) {
@ -86,7 +90,7 @@ export function bytesToNumberBE(bytes: Uint8Array): bigint {
return hexToNumber(bytesToHex(bytes)); return hexToNumber(bytesToHex(bytes));
} }
export function bytesToNumberLE(bytes: Uint8Array): bigint { export function bytesToNumberLE(bytes: Uint8Array): bigint {
if (!isBytes(bytes)) throw new Error('Uint8Array expected'); abytes(bytes);
return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse())); return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse()));
} }
@ -138,7 +142,7 @@ export function concatBytes(...arrays: Uint8Array[]): Uint8Array {
let sum = 0; let sum = 0;
for (let i = 0; i < arrays.length; i++) { for (let i = 0; i < arrays.length; i++) {
const a = arrays[i]; const a = arrays[i];
if (!isBytes(a)) throw new Error('Uint8Array expected'); abytes(a);
sum += a.length; sum += a.length;
} }
const res = new Uint8Array(sum); const res = new Uint8Array(sum);
@ -194,7 +198,7 @@ export function bitGet(n: bigint, pos: number) {
/** /**
* Sets single bit at position. * Sets single bit at position.
*/ */
export const bitSet = (n: bigint, pos: number, value: boolean) => { export function bitSet(n: bigint, pos: number, value: boolean) {
return n | ((value ? _1n : _0n) << BigInt(pos)); return n | ((value ? _1n : _0n) << BigInt(pos));
}; };