diff --git a/src/abstract/bls.ts b/src/abstract/bls.ts index 8da95e3..ab135a2 100644 --- a/src/abstract/bls.ts +++ b/src/abstract/bls.ts @@ -11,6 +11,7 @@ * 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. */ +import { AffinePoint } from './curve.js'; import { Field, hashToPrivateScalar } from './modular.js'; import { Hex, PrivKey, CHash, bitLen, bitGet, hexToBytes, bytesToHex } from './utils.js'; import * as htf from './hash-to-curve.js'; @@ -19,7 +20,6 @@ import { ProjPointType as ProjPointType, CurvePointsRes, weierstrassPoints, - AffinePoint, } from './weierstrass.js'; type Fp = bigint; // Can be different field? diff --git a/src/abstract/curve.ts b/src/abstract/curve.ts index f92f8ba..a54f36f 100644 --- a/src/abstract/curve.ts +++ b/src/abstract/curve.ts @@ -4,6 +4,11 @@ import { Field, validateField, nLength } from './modular.js'; const _0n = BigInt(0); const _1n = BigInt(1); +export type AffinePoint = { + x: T; + y: T; +} & { z?: never; t?: never }; + export interface Group> { double(): T; negate(): T; diff --git a/src/abstract/edwards.ts b/src/abstract/edwards.ts index 96fdec7..e37abb0 100644 --- a/src/abstract/edwards.ts +++ b/src/abstract/edwards.ts @@ -10,7 +10,14 @@ import { Hex, numberToBytesLE, } 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 const _0n = BigInt(0); @@ -28,7 +35,7 @@ export type CurveType = AbstractCurve & { domain?: (data: Uint8Array, ctx: Uint8Array, phflag: boolean) => Uint8Array; // Used for hashing uvRatio?: (u: bigint, v: bigint) => { isValid: boolean; value: bigint }; // Ratio √(u/v) preHash?: FHash; // RFC 8032 pre-hashing of messages to sign() / verify() - mapToCurve?: (scalar: bigint[]) => AffinePoint; // for hash-to-curve standard + mapToCurve?: (scalar: bigint[]) => AffinePoint; // for hash-to-curve standard }; function validateOpts(curve: CurveType) { @@ -49,29 +56,24 @@ function validateOpts(curve: CurveType) { 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 export interface ExtPointType extends Group { readonly ex: bigint; readonly ey: bigint; readonly ez: bigint; readonly et: bigint; + assertValidity(): void; multiply(scalar: bigint): ExtPointType; multiplyUnsafe(scalar: bigint): ExtPointType; isSmallOrder(): boolean; isTorsionFree(): boolean; - toAffine(iz?: bigint): AffinePoint; clearCofactor(): ExtPointType; + toAffine(iz?: bigint): AffinePoint; } // Static methods of Extended Point with coordinates in X, Y, Z, T export interface ExtPointConstructor extends GroupConstructor { new (x: bigint, y: bigint, z: bigint, t: bigint): ExtPointType; - fromAffine(p: AffinePoint): ExtPointType; + fromAffine(p: AffinePoint): ExtPointType; fromHex(hex: Hex): ExtPointType; fromPrivateKey(privateKey: Hex): ExtPointType; // TODO: remove } @@ -159,7 +161,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn { return this.toAffine().y; } - static fromAffine(p: AffinePoint): Point { + static fromAffine(p: AffinePoint): Point { if (p instanceof Point) throw new Error('extended point not allowed'); const { x, y } = p || {}; if (!in0MaskRange(x) || !in0MaskRange(y)) throw new Error('invalid affine point'); @@ -181,6 +183,8 @@ export function twistedEdwards(curveDef: CurveType): CurveFn { pointPrecomputes.delete(this); } + assertValidity(): void {} + // Compare one point to another. equals(other: Point): boolean { isPoint(other); @@ -309,7 +313,7 @@ export function twistedEdwards(curveDef: CurveType): CurveFn { // Converts Extended point to default (x, y) coordinates. // Can accept precomputed Z^-1 - for example, from invertBatch. - toAffine(iz?: bigint): AffinePoint { + toAffine(iz?: bigint): AffinePoint { const { ex: x, ey: y, ez: z } = this; const is0 = this.is0(); if (iz == null) iz = is0 ? _8n : (Fp.inv(z) as bigint); // 8 was chosen arbitrarily diff --git a/src/abstract/hash-to-curve.ts b/src/abstract/hash-to-curve.ts index 9acf594..75c94ad 100644 --- a/src/abstract/hash-to-curve.ts +++ b/src/abstract/hash-to-curve.ts @@ -1,5 +1,5 @@ /*! 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 { CHash, Hex, concatBytes, ensureBytes } from './utils.js'; @@ -182,11 +182,11 @@ export function isogenyMap>(field: F, map: [T[], T[], T[], }; } -type AffinePoint = { x: T; y: T }; export interface H2CPoint extends Group> { add(rhs: H2CPoint): H2CPoint; toAffine(iz?: bigint): AffinePoint; clearCofactor(): H2CPoint; + assertValidity(): void; } export interface H2CPointConstructor extends GroupConstructor> { @@ -216,9 +216,11 @@ export function hashToCurve( if (!mapToCurve) throw new Error('CURVE.mapToCurve() has not been defined'); msg = ensureBytes(msg); 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]))) .clearCofactor(); + P.assertValidity(); + return P; }, // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#section-3 @@ -226,7 +228,9 @@ export function hashToCurve( if (!mapToCurve) throw new Error('CURVE.mapToCurve() has not been defined'); msg = ensureBytes(msg); 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; }, }; } diff --git a/src/abstract/weierstrass.ts b/src/abstract/weierstrass.ts index 10b4afa..24e53d4 100644 --- a/src/abstract/weierstrass.ts +++ b/src/abstract/weierstrass.ts @@ -3,8 +3,16 @@ import * as mod from './modular.js'; import * as ut 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 EndomorphismOpts = { 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 */ -export type AffinePoint = { - x: T; - y: T; -} & { z?: never }; // Instance for 3d XYZ points export interface ProjPointType extends Group> { readonly px: T;