11import crypto from 'crypto'
22import Secp256r1 from '../Secp256r1.js'
3+ import { sha256 } from '../Hash.js'
34
45const curve = new Secp256r1 ( )
56
@@ -11,32 +12,72 @@ const THREE_G =
1112const toBase64Url = ( hex : string ) : string => Buffer . from ( hex , 'hex' ) . toString ( 'base64url' )
1213
1314describe ( 'Secp256r1' , ( ) => {
14- test ( 'base point multiplication matches known coordinates' , ( ) => {
15+ test ( 'base point multiplication matches known coordinates and handles infinity ' , ( ) => {
1516 const twoG = curve . multiplyBase ( 2n )
1617 const threeG = curve . multiplyBase ( 3n )
1718 expect ( curve . pointToHex ( twoG ) ) . toBe ( TWO_G )
1819 expect ( curve . pointToHex ( threeG ) ) . toBe ( THREE_G )
1920 expect ( curve . multiplyBase ( curve . n ) ) . toBeNull ( )
21+ expect ( curve . multiply ( null , 5n ) ) . toBeNull ( )
2022 } )
2123
22- test ( 'public key generation stays on-curve and supports compression' , ( ) => {
24+ test ( 'public key generation stays on-curve, supports compression, and rejects bad encodings ' , ( ) => {
2325 const priv = curve . generatePrivateKeyHex ( )
2426 const pub = curve . publicKeyFromPrivate ( priv )
2527 expect ( curve . isOnCurve ( pub ) ) . toBe ( true )
2628 const compressed = curve . pointToHex ( pub , true )
2729 const roundTrip = curve . pointFromHex ( compressed )
2830 expect ( roundTrip ) . toEqual ( pub )
31+ expect ( ( ) => curve . pointFromHex ( '05abcdef' ) ) . toThrow ( )
32+ expect ( ( ) => curve . pointFromHex ( '' ) ) . toThrow ( )
2933 } )
3034
31- test ( 'ECDSA sign and verify round-trip' , ( ) => {
35+ test ( 'adding inverse points yields infinity' , ( ) => {
36+ const p = curve . multiplyBase ( 9n )
37+ const neg = { x : p ! . x , y : curve . p - p ! . y }
38+ expect ( curve . add ( p , neg ) ) . toBeNull ( )
39+ expect ( curve . add ( null , p ) ) . toEqual ( p )
40+ } )
41+
42+ test ( 'ECDSA sign and verify round-trip, low-s enforced, rejects malformed inputs' , ( ) => {
3243 const priv = '1' . repeat ( 64 )
3344 const pub = curve . publicKeyFromPrivate ( priv )
3445 const message = Buffer . from ( 'p256 check' )
3546 const signature = curve . sign ( message , priv )
47+ const sVal = BigInt ( '0x' + signature . s )
48+ expect ( sVal <= curve . n / 2n ) . toBe ( true )
3649 expect ( curve . verify ( message , signature , pub ) ) . toBe ( true )
3750 expect ( curve . verify ( Buffer . from ( 'different' ) , signature , pub ) ) . toBe ( false )
3851 const tampered = { r : signature . r , s : signature . s . slice ( 0 , 62 ) + '00' }
3952 expect ( curve . verify ( message , tampered , pub ) ) . toBe ( false )
53+ const zeroR = { r : '0' . repeat ( 64 ) , s : signature . s }
54+ expect ( curve . verify ( message , zeroR , pub ) ) . toBe ( false )
55+ const zeroS = { r : signature . r , s : '0' . repeat ( 64 ) }
56+ expect ( curve . verify ( message , zeroS , pub ) ) . toBe ( false )
57+ expect ( curve . verify ( message , signature , '02deadbeef' ) ) . toBe ( false )
58+ } )
59+
60+ test ( 'deterministic nonce is stable across calls and message changes' , ( ) => {
61+ const priv = '2' . repeat ( 64 )
62+ const pub = curve . publicKeyFromPrivate ( priv )
63+ const message = Buffer . from ( 'deterministic nonce' )
64+ const sig1 = curve . sign ( message , priv )
65+ const sig2 = curve . sign ( message , priv )
66+ expect ( sig1 ) . toEqual ( sig2 )
67+ const sig3 = curve . sign ( Buffer . from ( 'deterministic nonce v2' ) , priv )
68+ expect ( sig3 ) . not . toEqual ( sig1 )
69+ expect ( curve . verify ( message , sig1 , pub ) ) . toBe ( true )
70+ } )
71+
72+ test ( 'prehashed signing path matches explicit hashing input' , ( ) => {
73+ const priv = '4' . repeat ( 64 )
74+ const pub = curve . publicKeyFromPrivate ( priv )
75+ const message = Buffer . from ( 'prehashed path' )
76+ const digest = new Uint8Array ( sha256 ( message ) )
77+ const sig1 = curve . sign ( message , priv )
78+ const sig2 = curve . sign ( digest , priv , { prehashed : true } )
79+ expect ( sig1 ) . toEqual ( sig2 )
80+ expect ( curve . verify ( digest , sig2 , pub , { prehashed : true } ) ) . toBe ( true )
4081 } )
4182
4283 test ( 'signatures interoperate with Node crypto (ieee-p1363 encoding)' , ( ) => {
0 commit comments