@@ -59,6 +59,10 @@ export class EccContext {
5959 * ```
6060 */
6161 static init ( lib : EccLib ) : EccContext {
62+ // Skip re-verification if same lib is already initialized
63+ if ( EccContext . #instance && EccContext . #instance. #lib === lib ) {
64+ return EccContext . #instance;
65+ }
6266 verifyEcc ( lib ) ;
6367 EccContext . #instance = new EccContext ( lib ) ;
6468 return EccContext . #instance;
@@ -177,32 +181,64 @@ export function getEccLib(): EccLib {
177181// ============================================================================
178182
179183interface TweakAddVector {
180- pubkey : string ;
181- tweak : string ;
184+ pubkey : Uint8Array ;
185+ tweak : Uint8Array ;
182186 parity : 0 | 1 | - 1 ;
183- result : string | null ;
187+ result : Uint8Array | null ;
188+ }
189+
190+ // Lazily decoded test vectors (decoded once on first verification)
191+ let _tweakVectors : TweakAddVector [ ] | undefined ;
192+ let _validPoints : Uint8Array [ ] | undefined ;
193+ let _invalidPoints : Uint8Array [ ] | undefined ;
194+
195+ function getTweakVectors ( ) : TweakAddVector [ ] {
196+ if ( ! _tweakVectors ) {
197+ _tweakVectors = [
198+ {
199+ pubkey : fromHex ( '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798' ) ,
200+ tweak : fromHex ( 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140' ) ,
201+ parity : - 1 ,
202+ result : null ,
203+ } ,
204+ {
205+ pubkey : fromHex ( '1617d38ed8d8657da4d4761e8057bc396ea9e4b9d29776d4be096016dbd2509b' ) ,
206+ tweak : fromHex ( 'a8397a935f0dfceba6ba9618f6451ef4d80637abf4e6af2669fbc9de6a8fd2ac' ) ,
207+ parity : 1 ,
208+ result : fromHex ( 'e478f99dab91052ab39a33ea35fd5e6e4933f4d28023cd597c9a1f6760346adf' ) ,
209+ } ,
210+ {
211+ pubkey : fromHex ( '2c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991' ) ,
212+ tweak : fromHex ( '823c3cd2142744b075a87eade7e1b8678ba308d566226a0056ca2b7a76f86b47' ) ,
213+ parity : 0 ,
214+ result : fromHex ( '9534f8dc8c6deda2dc007655981c78b49c5d96c778fbf363462a11ec9dfd948c' ) ,
215+ } ,
216+ ] ;
217+ }
218+ return _tweakVectors ;
184219}
185220
186- const TWEAK_ADD_VECTORS : TweakAddVector [ ] = [
187- {
188- pubkey : '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798' ,
189- tweak : 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140' ,
190- parity : - 1 ,
191- result : null ,
192- } ,
193- {
194- pubkey : '1617d38ed8d8657da4d4761e8057bc396ea9e4b9d29776d4be096016dbd2509b' ,
195- tweak : 'a8397a935f0dfceba6ba9618f6451ef4d80637abf4e6af2669fbc9de6a8fd2ac' ,
196- parity : 1 ,
197- result : 'e478f99dab91052ab39a33ea35fd5e6e4933f4d28023cd597c9a1f6760346adf' ,
198- } ,
199- {
200- pubkey : '2c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991' ,
201- tweak : '823c3cd2142744b075a87eade7e1b8678ba308d566226a0056ca2b7a76f86b47' ,
202- parity : 0 ,
203- result : '9534f8dc8c6deda2dc007655981c78b49c5d96c778fbf363462a11ec9dfd948c' ,
204- } ,
205- ] ;
221+ function getValidPoints ( ) : Uint8Array [ ] {
222+ if ( ! _validPoints ) {
223+ _validPoints = [
224+ fromHex ( '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798' ) ,
225+ fromHex ( 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffeeffffc2e' ) ,
226+ fromHex ( 'f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9' ) ,
227+ fromHex ( '0000000000000000000000000000000000000000000000000000000000000001' ) ,
228+ ] ;
229+ }
230+ return _validPoints ;
231+ }
232+
233+ function getInvalidPoints ( ) : Uint8Array [ ] {
234+ if ( ! _invalidPoints ) {
235+ _invalidPoints = [
236+ fromHex ( '0000000000000000000000000000000000000000000000000000000000000000' ) ,
237+ fromHex ( 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f' ) ,
238+ ] ;
239+ }
240+ return _invalidPoints ;
241+ }
206242
207243/**
208244 * Verifies that the ECC library implementation is correct.
@@ -216,29 +252,17 @@ function verifyEcc(ecc: EccLib): void {
216252 throw new Error ( 'ECC library missing isXOnlyPoint function' ) ;
217253 }
218254
219- // Test isXOnlyPoint with valid points
220- const validPoints = [
221- '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798' ,
222- 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffeeffffc2e' ,
223- 'f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9' ,
224- '0000000000000000000000000000000000000000000000000000000000000001' ,
225- ] ;
226-
227- for ( const hex of validPoints ) {
228- if ( ! ecc . isXOnlyPoint ( fromHex ( hex ) ) ) {
229- throw new Error ( `ECC library isXOnlyPoint failed for valid point: ${ hex } ` ) ;
255+ // Test isXOnlyPoint with valid points (pre-decoded)
256+ for ( const point of getValidPoints ( ) ) {
257+ if ( ! ecc . isXOnlyPoint ( point ) ) {
258+ throw new Error ( 'ECC library isXOnlyPoint failed for a valid point' ) ;
230259 }
231260 }
232261
233- // Test isXOnlyPoint with invalid points
234- const invalidPoints = [
235- '0000000000000000000000000000000000000000000000000000000000000000' ,
236- 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f' ,
237- ] ;
238-
239- for ( const hex of invalidPoints ) {
240- if ( ecc . isXOnlyPoint ( fromHex ( hex ) ) ) {
241- throw new Error ( `ECC library isXOnlyPoint should reject invalid point: ${ hex } ` ) ;
262+ // Test isXOnlyPoint with invalid points (pre-decoded)
263+ for ( const point of getInvalidPoints ( ) ) {
264+ if ( ecc . isXOnlyPoint ( point ) ) {
265+ throw new Error ( 'ECC library isXOnlyPoint should reject invalid point' ) ;
242266 }
243267 }
244268
@@ -247,33 +271,27 @@ function verifyEcc(ecc: EccLib): void {
247271 throw new Error ( 'ECC library missing xOnlyPointAddTweak function' ) ;
248272 }
249273
250- for ( const vector of TWEAK_ADD_VECTORS ) {
274+ for ( const vector of getTweakVectors ( ) ) {
251275 const result = ecc . xOnlyPointAddTweak (
252- fromHex ( vector . pubkey ) as XOnlyPublicKey ,
253- fromHex ( vector . tweak ) as Bytes32 ,
276+ vector . pubkey as XOnlyPublicKey ,
277+ vector . tweak as Bytes32 ,
254278 ) ;
255279
256280 if ( vector . result === null ) {
257281 if ( result !== null ) {
258282 throw new Error (
259- ` ECC library xOnlyPointAddTweak should return null for: ${ vector . pubkey } ` ,
283+ ' ECC library xOnlyPointAddTweak should return null for test vector' ,
260284 ) ;
261285 }
262286 } else {
263287 if ( result === null ) {
264- throw new Error (
265- `ECC library xOnlyPointAddTweak returned null unexpectedly for: ${ vector . pubkey } ` ,
266- ) ;
288+ throw new Error ( 'ECC library xOnlyPointAddTweak returned null unexpectedly' ) ;
267289 }
268290 if ( result . parity !== vector . parity ) {
269- throw new Error (
270- `ECC library xOnlyPointAddTweak parity mismatch for: ${ vector . pubkey } ` ,
271- ) ;
291+ throw new Error ( 'ECC library xOnlyPointAddTweak parity mismatch' ) ;
272292 }
273- if ( ! equals ( result . xOnlyPubkey , fromHex ( vector . result ) ) ) {
274- throw new Error (
275- `ECC library xOnlyPointAddTweak result mismatch for: ${ vector . pubkey } ` ,
276- ) ;
293+ if ( ! equals ( result . xOnlyPubkey , vector . result ) ) {
294+ throw new Error ( 'ECC library xOnlyPointAddTweak result mismatch' ) ;
277295 }
278296 }
279297 }
0 commit comments