@@ -47,20 +47,20 @@ const frz = (o: Object) => Object.freeze(o);
4747export interface AffinePoint { x : bigint , y : bigint }
4848/** Point in 3d xyz projective coordinates. 3d takes less inversions than 2d. */
4949class Point {
50- readonly X : bigint ;
51- readonly Y : bigint ;
52- readonly Z : bigint ;
50+ readonly px : bigint ;
51+ readonly py : bigint ;
52+ readonly pz : bigint ;
5353 constructor ( X : bigint , Y : bigint , Z : bigint ) {
54- this . X = afield0 ( X ) ;
55- this . Y = afield ( Y ) ; // y can't be 0 in 3d
56- this . Z = afield0 ( Z ) ;
54+ this . px = afield0 ( X ) ;
55+ this . py = afield ( Y ) ; // y can't be 0 in 3d
56+ this . pz = afield0 ( Z ) ;
5757 frz ( this ) ;
5858 }
5959 static from ( bytes : Bytes ) : Point {
6060 au8 ( bytes ) ;
6161 let p : Point | undefined = undefined ;
6262 const head = bytes [ 0 ] , tail = bytes . subarray ( 1 ) ; // first byte is prefix, rest is data
63- const x = sliceNum ( tail , 0 , L ) , len = bytes . length ; // next 32 bytes are x coordinate
63+ const x = slcNum ( tail , 0 , L ) , len = bytes . length ; // next 32 bytes are x coordinate
6464 if ( len === ( L + 1 ) && [ 0x02 , 0x03 ] . includes ( head ) ) { // compressed points: 33b, start
6565 // afield(x); // with byte 0x02 or 0x03. check 1<=x<P.
6666 let y = lift ( x ) ; // x³ + ax + b is right side of equation
@@ -69,19 +69,19 @@ class Point {
6969 if ( headOdd !== isYOdd ) y = M ( - y ) ; // determine proper solution
7070 p = new Point ( x , y , _1 ) ; // create point
7171 } // Uncompressed points: 65b, start with 0x04
72- if ( len === ( L2 + 1 ) && head === 0x04 ) p = new Point ( x , sliceNum ( tail , L , L2 ) , _1 ) ;
72+ if ( len === ( L2 + 1 ) && head === 0x04 ) p = new Point ( x , slcNum ( tail , L , L2 ) , _1 ) ;
7373 return p ? p . ok ( ) : err ( 'Point invalid: not on curve' ) ; // Verify the result
7474 }
7575 /** Equality check: compare points P&Q. */
7676 eql ( other : Point ) : boolean {
77- const { X : X1 , Y : Y1 , Z : Z1 } = this ;
78- const { X : X2 , Y : Y2 , Z : Z2 } = apoint ( other ) ; // isPoint() checks class equality
77+ const { px : X1 , py : Y1 , pz : Z1 } = this ;
78+ const { px : X2 , py : Y2 , pz : Z2 } = apoint ( other ) ; // isPoint() checks class equality
7979 const X1Z2 = M ( X1 * Z2 ) , X2Z1 = M ( X2 * Z1 ) ;
8080 const Y1Z2 = M ( Y1 * Z2 ) , Y2Z1 = M ( Y2 * Z1 ) ;
8181 return X1Z2 === X2Z1 && Y1Z2 === Y2Z1 ;
8282 }
8383 /** Flip point over y coordinate. */
84- neg ( ) : Point { return new Point ( this . X , M ( - this . Y ) , this . Z ) ; }
84+ neg ( ) : Point { return new Point ( this . px , M ( - this . py ) , this . pz ) ; }
8585 /** Point doubling: P+P, complete formula. */
8686 dbl ( ) : Point { return this . add ( this ) ; }
8787 /**
@@ -90,8 +90,8 @@ class Point {
9090 * Cost: 12M + 0S + 3*a + 3*b3 + 23add.
9191 */
9292 add ( other : Point ) : Point {
93- const { X : X1 , Y : Y1 , Z : Z1 } = this ;
94- const { X : X2 , Y : Y2 , Z : Z2 } = apoint ( other ) ;
93+ const { px : X1 , py : Y1 , pz : Z1 } = this ;
94+ const { px : X2 , py : Y2 , pz : Z2 } = apoint ( other ) ;
9595 const a = _0 , b = _b ;
9696 // const { a, b } = CURVE;
9797 let X3 = _0 , Y3 = _0 , Z3 = _0 ;
@@ -127,7 +127,7 @@ class Point {
127127 }
128128 /** Convert point to 2d xy affine point. (x, y, z) ∋ (x=x/z, y=y/z) */
129129 aff ( ) : AffinePoint {
130- const { X : x , Y : y , Z : z } = this ;
130+ const { px : x , py : y , pz : z } = this ;
131131 if ( this . eql ( I ) ) return { x : _0 , y : _0 } ; // fast-path for zero point
132132 if ( z === _1 ) return { x, y } ; // if z is 1, pass affine coordinates as-is
133133 const iz = inv ( z , P ) ; // z^-1: invert z
@@ -144,9 +144,13 @@ class Point {
144144 toBytes ( isCompressed = true ) : Bytes { // Encode point to Uint8Array.
145145 const { x, y } = this . ok ( ) . aff ( ) ; // convert to 2d xy affine point
146146 const head = isCompressed ? ( isEvenB ( y ) ? '02' : '03' ) : '04' ; // 0x02, 0x03, 0x04 prefix
147- const hex = head + numberToHex ( x ) + ( isCompressed ? '' : numberToHex ( y ) ) ; // prefix||x and ||y
147+ const hex = head + n2h ( x ) + ( isCompressed ? '' : n2h ( y ) ) ; // prefix||x and ||y
148148 return h2b ( hex ) ;
149149 }
150+
151+ // multiply(n: bigint): Point { return this.mul(n); } // Aliases to compress code
152+ // toAffine(): AffinePoint { return this.aff(); }
153+ // assertValidity(): Point { return this.ok(); }
150154}
151155// const { G, I } = Point; // Generator, identity points
152156const G = new Point ( Gx , Gy , _1 ) ; /** Generator / base point */
@@ -178,11 +182,11 @@ const h2b = (hex: string): Bytes => { // hex to bytes
178182 }
179183 return array ;
180184} ;
181- const bytesToNum = ( b : Bytes ) : bigint => BigInt ( '0x' + ( b2h ( b ) || '0' ) ) ; // bytes to number
182- const sliceNum = ( b : Bytes , from : number , to : number ) => bytesToNum ( b . subarray ( from , to ) ) ; // slice bytes num
185+ const b2n = ( b : Bytes ) : bigint => BigInt ( '0x' + ( b2h ( b ) || '0' ) ) ; // bytes to number
186+ const slcNum = ( b : Bytes , from : number , to : number ) => b2n ( b . subarray ( from , to ) ) ; // slice bytes num
183187const numTo32b = ( n : bigint ) : Bytes => h2b ( padh ( arange ( n , _0 , B256 ) , L2 ) ) ; // number to 32b. Must be 0 <= num < B256
184- const numberToHex = ( num : bigint ) : string => b2h ( numTo32b ( num ) ) ; // number to 32b hex
185- const concatBytes = ( ...arrs : Bytes [ ] ) : Bytes => { // concatenate Uint8Array-s
188+ const n2h = ( num : bigint ) : string => b2h ( numTo32b ( num ) ) ; // number to 32b hex
189+ const concatB = ( ...arrs : Bytes [ ] ) : Bytes => { // concatenate Uint8Array-s
186190 const r = u8n ( arrs . reduce ( ( sum , a ) => sum + au8 ( a ) . length , 0 ) ) ; // create u8a of summed length
187191 let pad = 0 ; // walk through each array,
188192 arrs . forEach ( a => { r . set ( a , pad ) ; pad += a . length } ) ; // ensure they have proper type
@@ -199,7 +203,7 @@ const inv = (num: bigint, md: bigint): bigint => { // modular inversion
199203 return b === _1 ? M ( x , md ) : err ( 'no inverse' ) ; // b is gcd at this point
200204} ;
201205const scalar = ( pr : Bytes ) : bigint => { // normalize private key to bigint
202- let num = bytesToNum ( au8 ( pr , L ) ) ; // convert to bigint when bytes
206+ let num = b2n ( au8 ( pr , L ) ) ; // convert to bigint when bytes
203207 return arange ( num , _1 , N , 'private key invalid 3' ) ; // check if bigint is in range
204208} ;
205209const highS = ( n : bigint ) : boolean => n > ( N >> _1 ) ; // if a number is bigger than CURVE.n/2
@@ -222,7 +226,7 @@ class Signature {
222226const bits2int = ( bytes : Bytes ) : bigint => { // RFC6979: ensure ECDSA msg is X bytes.
223227 const delta = bytes . length * 8 - 256 ; // RFC suggests optional truncating via bits2octets
224228 if ( delta > 1024 ) err ( 'msg invalid' ) ; // our CUSTOM check, "just-in-case"
225- const num = bytesToNum ( bytes ) ; // FIPS 186-4 4.6 suggests the leftmost min(nBitLen, outLen) bits, which
229+ const num = b2n ( bytes ) ; // FIPS 186-4 4.6 suggests the leftmost min(nBitLen, outLen) bits, which
226230 return delta > 0 ? num >> BigInt ( delta ) : num ; // matches bits2int. bits2int can produce res>N.
227231} ;
228232const bits2int_modN = ( bytes : Bytes ) : bigint => { // int2octets can't be used; pads small msgs
@@ -275,7 +279,7 @@ const prepSig = (msgh: Bytes, priv: Bytes, opts: OptS = optS): BC => {// prepare
275279 }
276280 return new Signature ( r , normS , rec ) as SignatureWithRecovery ; // use normS, not s
277281 } ;
278- return { seed : concatBytes ( ...seed ) , k2sig }
282+ return { seed : concatB ( ...seed ) , k2sig }
279283}
280284type Pred < T > = ( v : Uint8Array ) => T | undefined ;
281285const hmacDrbg = < T > ( asynchronous : boolean ) => { // HMAC-DRBG async
@@ -374,7 +378,7 @@ const verify = (sig: Bytes, msgh: Bytes, pub: Bytes, opts: OptV = optV): boolean
374378 let { lowS } = opts ; // ECDSA signature verification
375379 if ( lowS == null ) lowS = true ; // Default lowS=true
376380 let h : bigint , P : Point ; // secg.org/sec1-v2.pdf 4.1.4
377- let { r, s } = new Signature ( sliceNum ( sig , 0 , L ) , sliceNum ( sig , L , L2 ) ) // throw error when DER is suspected now.
381+ let { r, s } = new Signature ( slcNum ( sig , 0 , L ) , slcNum ( sig , L , L2 ) ) // throw error when DER is suspected now.
378382 try {
379383 h = bits2int_modN ( msgh ) ; // Truncate hash
380384 P = Point . from ( pub ) ; // Validate public key
@@ -402,7 +406,7 @@ const recoverPublicKey = (point: SignatureWithRecovery, msgh: Bytes): Point => {
402406 const radj = rec === 2 || rec === 3 ? r + N : r ; // If rec was 2 or 3, q.x is bigger than n
403407 afield ( radj ) ; // ensure q.x is still a field element
404408 const head = isEvenN ( rec ) ? '02' : '03' ; // head is 0x02 or 0x03
405- const R = Point . from ( h2b ( head + numberToHex ( radj ) ) ) ; // concat head + hex repr of r
409+ const R = Point . from ( h2b ( head + n2h ( radj ) ) ) ; // concat head + hex repr of r
406410 const ir = inv ( radj , N ) ; // r^-1
407411 const u1 = modN ( - h * ir ) ; // -hr^-1
408412 const u2 = modN ( s * ir ) ; // sr^-1
@@ -433,26 +437,26 @@ const etc = {
433437 const s = subtle ( ) ;
434438 const name = 'HMAC' ;
435439 const k = await s . importKey ( 'raw' , key , { name, hash :{ name :'SHA-256' } } , false , [ 'sign' ] ) ;
436- return u8n ( await s . sign ( name , k , concatBytes ( ...msgs ) ) ) ;
440+ return u8n ( await s . sign ( name , k , concatB ( ...msgs ) ) ) ;
437441 } ,
438442 hmacSha256Sync : undefined as HmacFnSync , // For TypeScript. Actual logic is below
439443 sha256Async : async ( ...msgs : Bytes [ ] ) : Promise < Bytes > => {
440- return u8n ( await subtle ( ) . digest ( "SHA-256" , concatBytes ( ...msgs ) ) ) ;
444+ return u8n ( await subtle ( ) . digest ( "SHA-256" , concatB ( ...msgs ) ) ) ;
441445 } ,
442446 sha256Sync : undefined as Sha256FnSync ,
443447} ;
444448const etc2 = {
445449 hexToBytes : h2b as ( hex : string ) => Bytes ,
446450 bytesToHex : b2h as ( bytes : Bytes ) => string ,
447- concatBytes : concatBytes as ( ...arrs : Bytes [ ] ) => Bytes ,
448- bytesToNumberBE : bytesToNum as ( a : Bytes ) => bigint ,
451+ concatBytes : concatB as ( ...arrs : Bytes [ ] ) => Bytes ,
452+ bytesToNumberBE : b2n as ( a : Bytes ) => bigint ,
449453 numberToBytesBE : numTo32b as ( n : bigint ) => Bytes ,
450454 mod : M as ( a : bigint , md ?: bigint ) => bigint ,
451455 invert : inv as ( num : bigint , md ?: bigint ) => bigint , // math utilities
452456 randomBytes : randomBytes as ( len ?: number ) => Bytes ,
453457}
454458const randomPrivateKey = ( ) : Bytes => {
455- const num = M ( bytesToNum ( randomBytes ( L + L / 2 ) ) , N - _1 ) ; // takes n+8 bytes
459+ const num = M ( b2n ( randomBytes ( L + L / 2 ) ) , N - _1 ) ; // takes n+8 bytes
456460 return numTo32b ( num + _1 ) ; // returns (hash mod n-1)+1
457461} ; // FIPS 186 B.4.1.
458462/** Curve-specific utilities for private keys. */
@@ -513,12 +517,12 @@ const T_CHALLENGE = 'challenge';
513517const taggedHash = ( tag : string , ...messages : Bytes [ ] ) : Bytes => {
514518 const fn = callEtcFn ( 'sha256Sync' ) ;
515519 const tagH = fn ( getTag ( tag ) ) ;
516- return fn ( concatBytes ( tagH , tagH , ...messages ) ) ;
520+ return fn ( concatB ( tagH , tagH , ...messages ) ) ;
517521} ;
518522const taggedHashAsync = async ( tag : string , ...messages : Bytes [ ] ) : Promise < Bytes > => { .0
519523 const fn = etc . sha256Async ;
520524 const tagH = await fn ( getTag ( tag ) ) ;
521- return await fn ( concatBytes ( tagH , tagH , ...messages ) ) ;
525+ return await fn ( concatB ( tagH , tagH , ...messages ) ) ;
522526} ;
523527
524528// ECDSA compact points are 33-byte. Schnorr is 32: we strip first byte 0x02 or 0x03
@@ -541,9 +545,9 @@ const lift = (x: bigint) => { // // Fail if x ≥ p. Let c = x³ + 7 mod p.
541545 return M ( r * r ) === n ? r : err ( 'sqrt invalid' ) ; // check if result is valid
542546}
543547const challenge = ( ...args : Bytes [ ] ) : bigint =>
544- modN ( bytesToNum ( taggedHash ( T_CHALLENGE , ...args ) ) ) ;
548+ modN ( b2n ( taggedHash ( T_CHALLENGE , ...args ) ) ) ;
545549const challengeAsync = async ( ...args : Bytes [ ] ) : Promise < bigint > =>
546- modN ( bytesToNum ( await taggedHashAsync ( T_CHALLENGE , ...args ) ) ) ;
550+ modN ( b2n ( await taggedHashAsync ( T_CHALLENGE , ...args ) ) ) ;
547551
548552/**
549553 * Schnorr public key is just `x` coordinate of Point as per BIP340.
@@ -559,7 +563,7 @@ const prepSigSchnorr = (message: Bytes, privateKey: Bytes, auxRand: Bytes) => {
559563}
560564
561565const extractK = ( rand : Bytes ) => {
562- const k_ = modN ( bytesToNum ( rand ) ) ; // Let k' = int(rand) mod n
566+ const k_ = modN ( b2n ( rand ) ) ; // Let k' = int(rand) mod n
563567 if ( k_ === _0 ) err ( 'sign failed: k is zero' ) ; // Fail if k' = 0.
564568 const { px, d } = extpubSchnorr ( numTo32b ( k_ ) ) ; // Let R = k'⋅G.
565569 return { rx : px , k : d }
@@ -585,7 +589,7 @@ const signSchnorr = (
585589) : Bytes => {
586590 const { m, px, d, a } = prepSigSchnorr ( message , privateKey , auxRand ) ;
587591 const aux = taggedHash ( T_AUX , a ) ;
588- const t = numTo32b ( d ^ bytesToNum ( aux ) ) ; // Let t be the byte-wise xor of bytes(d) and hash/aux(a)
592+ const t = numTo32b ( d ^ b2n ( aux ) ) ; // Let t be the byte-wise xor of bytes(d) and hash/aux(a)
589593 const rand = taggedHash ( T_NONCE , t , px , m ) ; // Let rand = hash/nonce(t || bytes(P) || m)
590594 const { rx, k } = extractK ( rand ) ;
591595 const e = challenge ( rx , px , m ) ; // Let e = int(hash/challenge(bytes(R) || bytes(P) || m)) mod n.
@@ -596,7 +600,7 @@ const signSchnorr = (
596600const signAsyncSchnorr = async ( message : Bytes , privateKey : Bytes , auxRand : Bytes = randomBytes ( L ) ) : Promise < Bytes > => {
597601 const { m, px, d, a } = prepSigSchnorr ( message , privateKey , auxRand ) ;
598602 const aux = await taggedHashAsync ( T_AUX , a ) ;
599- const t = numTo32b ( d ^ bytesToNum ( aux ) ) ; // Let t be the byte-wise xor of bytes(d) and hash/aux(a)
603+ const t = numTo32b ( d ^ b2n ( aux ) ) ; // Let t be the byte-wise xor of bytes(d) and hash/aux(a)
600604 const rand = await taggedHashAsync ( T_NONCE , t , px , m ) ; // Let rand = hash/nonce(t || bytes(P) || m)
601605 const { rx, k } = extractK ( rand ) ;
602606 const e = await challengeAsync ( rx , px , m ) ; // Let e = int(hash/challenge(bytes(R) || bytes(P) || m)) mod n.
@@ -619,16 +623,16 @@ const verifSchnorr = (signature: Bytes, message: Bytes, publicKey: Bytes, sync =
619623 const pub = au8 ( publicKey , L ) ;
620624 // lift_x from BIP340. Convert 32-byte x coordinate to elliptic curve point.
621625 // Fail if x ≥ p. Let c = x³ + 7 mod p.
622- const x = bytesToNum ( pub ) ;
626+ const x = b2n ( pub ) ;
623627 const y = lift ( x ) ; // Let y = c^(p+1)/4 mod p.
624628 // Return the unique point P such that x(P) = x and
625629 const P_ = new Point ( x , isEvenB ( y ) ? y : M ( - y ) , _1 ) . ok ( ) ; // y(P) = y if y mod 2 = 0 or y(P) = p-y otherwise.
626630 // P = lift_x(int(pk)); fail if that fails
627- const r = sliceNum ( sig , 0 , L ) ; // Let r = int(sig[0:32]); fail if r ≥ p.
631+ const r = slcNum ( sig , 0 , L ) ; // Let r = int(sig[0:32]); fail if r ≥ p.
628632 arange ( r , _1 , P ) ;
629- const s = sliceNum ( sig , L , L2 ) ; // Let s = int(sig[32:64]); fail if s ≥ n.
633+ const s = slcNum ( sig , L , L2 ) ; // Let s = int(sig[32:64]); fail if s ≥ n.
630634 arange ( s , _1 , N ) ;
631- const i = concatBytes ( numTo32b ( r ) , pointToBytes ( P_ ) , msg ) ;
635+ const i = concatB ( numTo32b ( r ) , pointToBytes ( P_ ) , msg ) ;
632636 if ( sync ) return finishVerif ( P_ , r , s , challenge ( i ) ) ; // int(challenge(bytes(r)||bytes(P)||m))%n
633637 return challengeAsync ( i ) . then ( e => finishVerif ( P_ , r , s , e ) ) ;
634638 } catch ( error ) {
0 commit comments