@@ -44,22 +44,30 @@ export const biModInv = (a: bigint): bigint => { // binary‑ext GCD
4444export const biModSqr = ( a : bigint ) : bigint => biModMul ( a , a )
4545
4646export const biModPow = ( base : bigint , exp : bigint ) : bigint => {
47- let result = BI_ONE
47+ let result = 1n
4848 base = biMod ( base )
49- let e = exp
50- while ( e > BI_ZERO ) {
51- if ( ( e & BI_ONE ) === BI_ONE ) result = biModMul ( result , base )
49+
50+ while ( exp > 0n ) {
51+ if ( ( exp & 1n ) !== 0n ) {
52+ result = biModMul ( result , base )
53+ }
5254 base = biModMul ( base , base )
53- e >>= BI_ONE
55+ exp >>= 1n
5456 }
57+
5558 return result
5659}
5760
5861export const P_PLUS1_DIV4 = ( P_BIGINT + 1n ) >> 2n
5962
6063export const biModSqrt = ( a : bigint ) : bigint | null => {
6164 const r = biModPow ( a , P_PLUS1_DIV4 )
62- return biModMul ( r , r ) === biMod ( a ) ? r : null
65+
66+ if ( biModMul ( r , r ) !== biMod ( a ) ) {
67+ return null
68+ }
69+
70+ return r
6371}
6472
6573const toBigInt = ( x : BigNumber | number | number [ ] | string ) : bigint => {
@@ -220,6 +228,13 @@ export default class Point extends BasePoint {
220228 y : BigNumber | null
221229 inf : boolean
222230
231+ static _assertOnCurve ( p : Point ) : Point {
232+ if ( ! p . validate ( ) ) {
233+ throw new Error ( 'Invalid point' )
234+ }
235+ return p
236+ }
237+
223238 /**
224239 * Creates a point object from a given Array. These numbers can represent coordinates in hex format, or points
225240 * in multiple established formats.
@@ -238,7 +253,6 @@ export default class Point extends BasePoint {
238253 */
239254 static fromDER ( bytes : number [ ] ) : Point {
240255 const len = 32
241- // uncompressed, hybrid-odd, hybrid-even
242256 if (
243257 ( bytes [ 0 ] === 0x04 || bytes [ 0 ] === 0x06 || bytes [ 0 ] === 0x07 ) &&
244258 bytes . length - 1 === 2 * len
@@ -258,12 +272,14 @@ export default class Point extends BasePoint {
258272 bytes . slice ( 1 + len , 1 + 2 * len )
259273 )
260274
261- return res
275+ return Point . _assertOnCurve ( res )
262276 } else if (
263277 ( bytes [ 0 ] === 0x02 || bytes [ 0 ] === 0x03 ) &&
264278 bytes . length - 1 === len
265279 ) {
266- return Point . fromX ( bytes . slice ( 1 , 1 + len ) , bytes [ 0 ] === 0x03 )
280+ return Point . _assertOnCurve (
281+ Point . fromX ( bytes . slice ( 1 , 1 + len ) , bytes [ 0 ] === 0x03 )
282+ )
267283 }
268284 throw new Error ( 'Unknown point format' )
269285 }
@@ -287,7 +303,7 @@ export default class Point extends BasePoint {
287303 */
288304 static fromString ( str : string ) : Point {
289305 const bytes = toArray ( str , 'hex' )
290- return Point . fromDER ( bytes )
306+ return Point . _assertOnCurve ( Point . fromDER ( bytes ) )
291307 }
292308
293309 /**
@@ -308,16 +324,22 @@ export default class Point extends BasePoint {
308324 static fromX ( x : BigNumber | number | number [ ] | string , odd : boolean ) : Point {
309325 let xBigInt = toBigInt ( x )
310326 xBigInt = biMod ( xBigInt )
327+
311328 const y2 = biModAdd ( biModMul ( biModSqr ( xBigInt ) , xBigInt ) , 7n )
312329 const y = biModSqrt ( y2 )
313- if ( y === null ) throw new Error ( 'Invalid point' )
330+ if ( y === null ) {
331+ throw new Error ( 'Invalid point' )
332+ }
333+
314334 let yBig = y
315335 if ( ( yBig & BI_ONE ) !== ( odd ? BI_ONE : BI_ZERO ) ) {
316336 yBig = biModSub ( P_BIGINT , yBig )
317337 }
338+
318339 const xBN = new BigNumber ( xBigInt . toString ( 16 ) , 16 )
319340 const yBN = new BigNumber ( yBig . toString ( 16 ) , 16 )
320- return new Point ( xBN , yBN )
341+
342+ return Point . _assertOnCurve ( new Point ( xBN , yBN ) )
321343 }
322344
323345 /**
@@ -339,33 +361,45 @@ export default class Point extends BasePoint {
339361 if ( typeof obj === 'string' ) {
340362 obj = JSON . parse ( obj )
341363 }
342- const res = new Point ( obj [ 0 ] , obj [ 1 ] , isRed )
343- if ( typeof obj [ 2 ] !== 'object' ) {
364+
365+ let res = new Point ( obj [ 0 ] , obj [ 1 ] , isRed )
366+ res = Point . _assertOnCurve ( res )
367+
368+ if ( typeof obj [ 2 ] !== 'object' || obj [ 2 ] === null ) {
344369 return res
345370 }
346371
347- const obj2point = ( obj ) : Point => {
348- return new Point ( obj [ 0 ] , obj [ 1 ] , isRed )
372+ const pre = obj [ 2 ]
373+
374+ const obj2point = ( p ) : Point => {
375+ const pt = new Point ( p [ 0 ] , p [ 1 ] , isRed )
376+ return Point . _assertOnCurve ( pt )
349377 }
350378
351- const pre = obj [ 2 ]
352379 res . precomputed = {
353380 beta : null ,
381+
354382 doubles :
355383 typeof pre . doubles === 'object' && pre . doubles !== null
356384 ? {
357385 step : pre . doubles . step ,
358- points : [ res ] . concat ( pre . doubles . points . map ( obj2point ) )
386+ points : [ res ] . concat (
387+ pre . doubles . points . map ( obj2point )
388+ )
359389 }
360390 : undefined ,
391+
361392 naf :
362393 typeof pre . naf === 'object' && pre . naf !== null
363394 ? {
364395 wnd : pre . naf . wnd ,
365- points : [ res ] . concat ( pre . naf . points . map ( obj2point ) )
396+ points : [ res ] . concat (
397+ pre . naf . points . map ( obj2point )
398+ )
366399 }
367400 : undefined
368401 }
402+
369403 return res
370404 }
371405
@@ -426,7 +460,20 @@ export default class Point extends BasePoint {
426460 * const isValid = aPoint.validate();
427461 */
428462 validate ( ) : boolean {
429- return this . curve . validate ( this )
463+ if ( this . inf || this . x == null || this . y == null ) return false
464+
465+ try {
466+ const xBig = BigInt ( '0x' + this . x . fromRed ( ) . toString ( 16 ) )
467+ const yBig = BigInt ( '0x' + this . y . fromRed ( ) . toString ( 16 ) )
468+
469+ // compute y² and x³ + 7 using bigint-secure field ops
470+ const lhs = biModMul ( yBig , yBig )
471+ const rhs = biModAdd ( biModMul ( biModMul ( xBig , xBig ) , xBig ) , 7n )
472+
473+ return lhs === rhs
474+ } catch {
475+ return false
476+ }
430477 }
431478
432479 /**
0 commit comments