hash-to-curve: assertValidity

This commit is contained in:
Paul Miller 2023-01-26 05:14:12 +00:00
parent 69b3ab5a57
commit 4ef2cad685
No known key found for this signature in database
GPG Key ID: 697079DA6878B89B
5 changed files with 39 additions and 22 deletions

@ -11,6 +11,7 @@
* We are using Fp for private keys (shorter) and Fp for signatures (longer). * We are using Fp for private keys (shorter) and Fp for signatures (longer).
* Some projects may prefer to swap this relation, it is not supported for now. * Some projects may prefer to swap this relation, it is not supported for now.
*/ */
import { AffinePoint } from './curve.js';
import { Field, hashToPrivateScalar } from './modular.js'; import { Field, hashToPrivateScalar } from './modular.js';
import { Hex, PrivKey, CHash, bitLen, bitGet, hexToBytes, bytesToHex } from './utils.js'; import { Hex, PrivKey, CHash, bitLen, bitGet, hexToBytes, bytesToHex } from './utils.js';
import * as htf from './hash-to-curve.js'; import * as htf from './hash-to-curve.js';
@ -19,7 +20,6 @@ import {
ProjPointType as ProjPointType, ProjPointType as ProjPointType,
CurvePointsRes, CurvePointsRes,
weierstrassPoints, weierstrassPoints,
AffinePoint,
} from './weierstrass.js'; } from './weierstrass.js';
type Fp = bigint; // Can be different field? type Fp = bigint; // Can be different field?

@ -4,6 +4,11 @@ import { Field, validateField, nLength } from './modular.js';
const _0n = BigInt(0); const _0n = BigInt(0);
const _1n = BigInt(1); const _1n = BigInt(1);
export type AffinePoint<T> = {
x: T;
y: T;
} & { z?: never; t?: never };
export interface Group<T extends Group<T>> { export interface Group<T extends Group<T>> {
double(): T; double(): T;
negate(): T; negate(): T;

@ -10,7 +10,14 @@ import {
Hex, Hex,
numberToBytesLE, numberToBytesLE,
} from './utils.js'; } from './utils.js';
import { Group, GroupConstructor, wNAF, AbstractCurve, validateAbsOpts } from './curve.js'; import {
Group,
GroupConstructor,
wNAF,
AbstractCurve,
validateAbsOpts,
AffinePoint,
} from './curve.js';
// Be friendly to bad ECMAScript parsers by not using bigint literals like 123n // Be friendly to bad ECMAScript parsers by not using bigint literals like 123n
const _0n = BigInt(0); const _0n = BigInt(0);
@ -28,7 +35,7 @@ export type CurveType = AbstractCurve<bigint> & {
domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array; // Used for hashing domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array; // Used for hashing
uvRatio?: (u: bigint, v: bigint) => { isValid: boolean; value: bigint }; // Ratio √(u/v) uvRatio?: (u: bigint, v: bigint) => { isValid: boolean; value: bigint }; // Ratio √(u/v)
preHash?: FHash; // RFC 8032 pre-hashing of messages to sign() / verify() preHash?: FHash; // RFC 8032 pre-hashing of messages to sign() / verify()
mapToCurve?: (scalar: bigint[]) => AffinePoint; // for hash-to-curve standard mapToCurve?: (scalar: bigint[]) => AffinePoint<bigint>; // for hash-to-curve standard
}; };
function validateOpts(curve: CurveType) { function validateOpts(curve: CurveType) {
@ -49,29 +56,24 @@ function validateOpts(curve: CurveType) {
return Object.freeze({ ...opts } as const); return Object.freeze({ ...opts } as const);
} }
// 2d point in XY coords
export type AffinePoint = {
x: bigint;
y: bigint;
} & { z?: never; t?: never };
// Instance of Extended Point with coordinates in X, Y, Z, T // Instance of Extended Point with coordinates in X, Y, Z, T
export interface ExtPointType extends Group<ExtPointType> { export interface ExtPointType extends Group<ExtPointType> {
readonly ex: bigint; readonly ex: bigint;
readonly ey: bigint; readonly ey: bigint;
readonly ez: bigint; readonly ez: bigint;
readonly et: bigint; readonly et: bigint;
assertValidity(): void;
multiply(scalar: bigint): ExtPointType; multiply(scalar: bigint): ExtPointType;
multiplyUnsafe(scalar: bigint): ExtPointType; multiplyUnsafe(scalar: bigint): ExtPointType;
isSmallOrder(): boolean; isSmallOrder(): boolean;
isTorsionFree(): boolean; isTorsionFree(): boolean;
toAffine(iz?: bigint): AffinePoint;
clearCofactor(): ExtPointType; clearCofactor(): ExtPointType;
toAffine(iz?: bigint): AffinePoint<bigint>;
} }
// Static methods of Extended Point with coordinates in X, Y, Z, T // Static methods of Extended Point with coordinates in X, Y, Z, T
export interface ExtPointConstructor extends GroupConstructor<ExtPointType> { export interface ExtPointConstructor extends GroupConstructor<ExtPointType> {
new (x: bigint, y: bigint, z: bigint, t: bigint): ExtPointType; new (x: bigint, y: bigint, z: bigint, t: bigint): ExtPointType;
fromAffine(p: AffinePoint): ExtPointType; fromAffine(p: AffinePoint<bigint>): ExtPointType;
fromHex(hex: Hex): ExtPointType; fromHex(hex: Hex): ExtPointType;
fromPrivateKey(privateKey: Hex): ExtPointType; // TODO: remove fromPrivateKey(privateKey: Hex): ExtPointType; // TODO: remove
} }
@ -159,7 +161,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
return this.toAffine().y; return this.toAffine().y;
} }
static fromAffine(p: AffinePoint): Point { static fromAffine(p: AffinePoint<bigint>): Point {
if (p instanceof Point) throw new Error('extended point not allowed'); if (p instanceof Point) throw new Error('extended point not allowed');
const { x, y } = p || {}; const { x, y } = p || {};
if (!in0MaskRange(x) || !in0MaskRange(y)) throw new Error('invalid affine point'); if (!in0MaskRange(x) || !in0MaskRange(y)) throw new Error('invalid affine point');
@ -181,6 +183,8 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
pointPrecomputes.delete(this); pointPrecomputes.delete(this);
} }
assertValidity(): void {}
// Compare one point to another. // Compare one point to another.
equals(other: Point): boolean { equals(other: Point): boolean {
isPoint(other); isPoint(other);
@ -309,7 +313,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn {
// Converts Extended point to default (x, y) coordinates. // Converts Extended point to default (x, y) coordinates.
// Can accept precomputed Z^-1 - for example, from invertBatch. // Can accept precomputed Z^-1 - for example, from invertBatch.
toAffine(iz?: bigint): AffinePoint { toAffine(iz?: bigint): AffinePoint<bigint> {
const { ex: x, ey: y, ez: z } = this; const { ex: x, ey: y, ez: z } = this;
const is0 = this.is0(); const is0 = this.is0();
if (iz == null) iz = is0 ? _8n : (Fp.inv(z) as bigint); // 8 was chosen arbitrarily if (iz == null) iz = is0 ? _8n : (Fp.inv(z) as bigint); // 8 was chosen arbitrarily

@ -1,5 +1,5 @@
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
import type { Group, GroupConstructor } from './curve.js'; import type { Group, GroupConstructor, AffinePoint } from './curve.js';
import { mod, Field } from './modular.js'; import { mod, Field } from './modular.js';
import { CHash, Hex, concatBytes, ensureBytes } from './utils.js'; import { CHash, Hex, concatBytes, ensureBytes } from './utils.js';
@ -182,11 +182,11 @@ export function isogenyMap<T, F extends Field<T>>(field: F, map: [T[], T[], T[],
}; };
} }
type AffinePoint<T> = { x: T; y: T };
export interface H2CPoint<T> extends Group<H2CPoint<T>> { export interface H2CPoint<T> extends Group<H2CPoint<T>> {
add(rhs: H2CPoint<T>): H2CPoint<T>; add(rhs: H2CPoint<T>): H2CPoint<T>;
toAffine(iz?: bigint): AffinePoint<T>; toAffine(iz?: bigint): AffinePoint<T>;
clearCofactor(): H2CPoint<T>; clearCofactor(): H2CPoint<T>;
assertValidity(): void;
} }
export interface H2CPointConstructor<T> extends GroupConstructor<H2CPoint<T>> { export interface H2CPointConstructor<T> extends GroupConstructor<H2CPoint<T>> {
@ -216,9 +216,11 @@ export function hashToCurve<T>(
if (!mapToCurve) throw new Error('CURVE.mapToCurve() has not been defined'); if (!mapToCurve) throw new Error('CURVE.mapToCurve() has not been defined');
msg = ensureBytes(msg); msg = ensureBytes(msg);
const u = hash_to_field(msg, 2, { ...def, DST: def.DST, ...options } as Opts); const u = hash_to_field(msg, 2, { ...def, DST: def.DST, ...options } as Opts);
return Point.fromAffine(mapToCurve(u[0])) const P = Point.fromAffine(mapToCurve(u[0]))
.add(Point.fromAffine(mapToCurve(u[1]))) .add(Point.fromAffine(mapToCurve(u[1])))
.clearCofactor(); .clearCofactor();
P.assertValidity();
return P;
}, },
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-3 // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-3
@ -226,7 +228,9 @@ export function hashToCurve<T>(
if (!mapToCurve) throw new Error('CURVE.mapToCurve() has not been defined'); if (!mapToCurve) throw new Error('CURVE.mapToCurve() has not been defined');
msg = ensureBytes(msg); msg = ensureBytes(msg);
const u = hash_to_field(msg, 1, { ...def, DST: def.encodeDST, ...options } as Opts); const u = hash_to_field(msg, 1, { ...def, DST: def.encodeDST, ...options } as Opts);
return Point.fromAffine(mapToCurve(u[0])).clearCofactor(); const P = Point.fromAffine(mapToCurve(u[0])).clearCofactor();
P.assertValidity();
return P;
}, },
}; };
} }

@ -3,8 +3,16 @@
import * as mod from './modular.js'; import * as mod from './modular.js';
import * as ut from './utils.js'; import * as ut from './utils.js';
import { Hex, PrivKey, ensureBytes, CHash } from './utils.js'; import { Hex, PrivKey, ensureBytes, CHash } from './utils.js';
import { Group, GroupConstructor, wNAF, AbstractCurve, validateAbsOpts } from './curve.js'; import {
Group,
GroupConstructor,
wNAF,
AbstractCurve,
validateAbsOpts,
AffinePoint,
} from './curve.js';
export type { AffinePoint };
type HmacFnSync = (key: Uint8Array, ...messages: Uint8Array[]) => Uint8Array; type HmacFnSync = (key: Uint8Array, ...messages: Uint8Array[]) => Uint8Array;
type EndomorphismOpts = { type EndomorphismOpts = {
beta: bigint; beta: bigint;
@ -55,10 +63,6 @@ export type VerOpts = { lowS?: boolean; prehash?: boolean };
* TODO: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#unique-symbol * TODO: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#unique-symbol
*/ */
export type AffinePoint<T> = {
x: T;
y: T;
} & { z?: never };
// Instance for 3d XYZ points // Instance for 3d XYZ points
export interface ProjPointType<T> extends Group<ProjPointType<T>> { export interface ProjPointType<T> extends Group<ProjPointType<T>> {
readonly px: T; readonly px: T;