@@ -145,18 +145,17 @@ const pub = ed25519.getPublicKey(priv);
145
145
const msg = new TextEncoder ().encode (' hello' );
146
146
const sig = ed25519 .sign (msg , priv );
147
147
ed25519 .verify (sig , msg , pub ); // Default mode: follows ZIP215
148
- ed25519 .verify (sig , msg , pub , { zip215: false }); // RFC8032 / FIPS 186-5
148
+ ed25519 .verify (sig , msg , pub , { zip215: false }); // SBS / e-voting / RFC8032 / FIPS 186-5
149
149
150
150
// Variants from RFC8032: with context, prehashed
151
151
import { ed25519ctx , ed25519ph } from ' @noble/curves/ed25519' ;
152
152
```
153
153
154
- Default ` verify ` behavior follows [ ZIP215] ( https://zips.z.cash/zip-0215 ) and
155
- [ can be used in consensus-critical applications] ( https://hdevalence.ca/blog/2020-10-04-its-25519am ) .
154
+ Default ` verify ` behavior follows ZIP215 and
155
+ can be used in consensus-critical applications.
156
156
It has SUF-CMA (strong unforgeability under chosen message attacks).
157
- ` zip215: false ` option switches verification criteria to strict
158
- [ RFC8032] ( https://www.rfc-editor.org/rfc/rfc8032 ) / [ FIPS 186-5] ( https://csrc.nist.gov/publications/detail/fips/186/5/final )
159
- and additionally provides [ non-repudiation with SBS] ( #edwards-twisted-edwards-curve ) .
157
+ If you need SBS (Strongly Binding Signatures) and FIPS 186-5 compliance,
158
+ use ` zip215: false ` . Check out [ Edwards Signatures section for more info] ( #edwards-twisted-edwards-curve ) .
160
159
161
160
X25519 follows [ RFC7748] ( https://www.rfc-editor.org/rfc/rfc7748 ) .
162
161
@@ -353,171 +352,69 @@ method: check out examples.
353
352
354
353
``` ts
355
354
import { weierstrass } from ' @noble/curves/abstract/weierstrass' ;
356
- import { Field } from ' @noble/curves/abstract/modular' ; // finite field for mod arithmetics
357
- import { sha256 } from ' @noble/hashes/sha256' ; // 3rd-party sha256() of type utils.CHash
358
- import { hmac } from ' @noble/hashes/hmac' ; // 3rd-party hmac() that will accept sha256()
359
- import { concatBytes , randomBytes } from ' @noble/hashes/utils' ; // 3rd-party utilities
355
+ import { Field } from ' @noble/curves/abstract/modular' ;
356
+ import { sha256 } from ' @noble/hashes/sha256' ;
357
+ import { hmac } from ' @noble/hashes/hmac' ;
358
+ import { concatBytes , randomBytes } from ' @noble/hashes/utils' ;
360
359
361
360
const hmacSha256 = (key : Uint8Array , ... msgs : Uint8Array []) =>
362
361
hmac (sha256 , key , concatBytes (... msgs ));
363
362
364
- // secq256k1: cycle of secp256k1 with Fp/N flipped.
363
+ // secQ (not secP) - secq256k1 is a cycle of secp256k1 with Fp/N flipped.
365
364
// https://personaelabs.org/posts/spartan-ecdsa
366
365
// https://zcash.github.io/halo2/background/curves.html#cycles-of-curves
367
366
const secq256k1 = weierstrass ({
368
- // Curve equation params a, b
369
367
a: 0n ,
370
368
b: 7n ,
371
- // Field over which we'll do calculations
372
369
Fp: Field (2n ** 256n - 432420386565659656852420866394968145599n ),
373
- // Curve order, total count of valid points in the field.
374
370
n: 2n ** 256n - 2n ** 32n - 2n ** 9n - 2n ** 8n - 2n ** 7n - 2n ** 6n - 2n ** 4n - 1n ,
375
- // Base point (x, y) aka generator point
376
371
Gx: 55066263022277343669578718895168534326250603453777594175500187360389116729240n ,
377
372
Gy: 32670510020758816978083085130507043184471273380659243275938904335757337482424n ,
378
-
379
373
hash: sha256 ,
380
374
hmac: hmacSha256 ,
381
375
randomBytes ,
382
376
});
383
377
384
- // NIST secp192r1 aka p192 https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/secg/secp192r1
378
+ // NIST secp192r1 aka p192
379
+ // https://www.secg.org/sec2-v2.pdf, https://neuromancer.sk/std/secg/secp192r1
385
380
const secp192r1 = weierstrass ({
386
- a: BigInt (' 0xfffffffffffffffffffffffffffffffefffffffffffffffc' ),
387
- b: BigInt (' 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1' ),
388
- Fp: Field (BigInt (' 0xfffffffffffffffffffffffffffffffeffffffffffffffff' )),
389
- n: BigInt (' 0xffffffffffffffffffffffff99def836146bc9b1b4d22831' ),
390
- Gx: BigInt (' 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012' ),
391
- Gy: BigInt (' 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811' ),
392
- h: BigInt (1 ),
381
+ a: 0xfffffffffffffffffffffffffffffffefffffffffffffffcn ,
382
+ b: 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1n ,
383
+ Fp: Field (0xfffffffffffffffffffffffffffffffeffffffffffffffffn ),
384
+ n: 0xffffffffffffffffffffffff99def836146bc9b1b4d22831n ,
385
+ Gx: 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012n ,
386
+ Gy: 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811n ,
393
387
hash: sha256 ,
394
388
hmac: hmacSha256 ,
395
389
randomBytes ,
396
390
});
397
-
398
- // Replace weierstrass() with weierstrassPoints() if you don't need ECDSA, hash, hmac, randomBytes
399
391
```
400
392
401
393
Short Weierstrass curve's formula is ` y² = x³ + ax + b ` . ` weierstrass `
402
394
expects arguments ` a ` , ` b ` , field ` Fp ` , curve order ` n ` , cofactor ` h `
403
395
and coordinates ` Gx ` , ` Gy ` of generator point.
404
-
405
- ** ` k ` generation** is done deterministically, following
406
- [ RFC6979] ( https://www.rfc-editor.org/rfc/rfc6979 ) . It is suggested to use ` extraEntropy `
407
- option, which incorporates randomness into signatures to increase their security.
408
-
409
- For k generation, specifying ` hmac ` & ` hash ` is required,
410
- which in our implementations is done by noble-hashes. If
411
- you're using different hashing library, make sure to wrap it in the following interface:
412
-
413
- ``` ts
414
- type CHash = {
415
- (message : Uint8Array ): Uint8Array ;
416
- blockLen: number ;
417
- outputLen: number ;
418
- create(): any ;
419
- };
420
-
421
- // example
422
- function sha256(message : Uint8Array ) {
423
- return _internal_lowlvl (message );
424
- }
425
- sha256 .outputLen = 32 ; // 32 bytes of output for sha2-256
426
- ```
427
-
428
- ** Message hash** is expected instead of message itself:
429
-
430
- - ` sign(msgHash, privKey) ` is default behavior, assuming you pre-hash msg with sha2, or other hash
431
- - ` sign(msg, privKey, {prehash: true}) ` option can be used if you want to pass the message itself
396
+ ` hmac ` and ` hash ` must be specified for deterministic ` k ` generation.
432
397
433
398
** Weierstrass points:**
434
399
435
- 1 . Exported as ` ProjectivePoint `
436
- 2 . Represented in projective (homogeneous) coordinates: (x, y, z) ∋ (x=x/z, y=y/z)
437
- 3 . Use complete exception-free formulas for addition and doubling
438
- 4 . Can be decoded/encoded from/to Uint8Array / hex strings using
439
- ` ProjectivePoint.fromHex ` and ` ProjectivePoint#toRawBytes() `
440
- 5 . Have ` assertValidity() ` which checks for being on-curve
441
- 6 . Have ` toAffine() ` and ` x ` / ` y ` getters which convert to 2d xy affine coordinates
442
-
443
- ``` ts
444
- // `weierstrassPoints()` returns `CURVE` and `ProjectivePoint`
445
- // `weierstrass()` returns `CurveFn`
446
- type SignOpts = { lowS? : boolean ; prehash? : boolean ; extraEntropy: boolean | Uint8Array };
447
- type CurveFn = {
448
- CURVE: ReturnType <typeof validateOpts >;
449
- getPublicKey: (privateKey : PrivKey , isCompressed ? : boolean ) => Uint8Array ;
450
- getSharedSecret: (privateA : PrivKey , publicB : Hex , isCompressed ? : boolean ) => Uint8Array ;
451
- sign: (msgHash : Hex , privKey : PrivKey , opts ? : SignOpts ) => SignatureType ;
452
- verify: (
453
- signature : Hex | SignatureType ,
454
- msgHash : Hex ,
455
- publicKey : Hex ,
456
- opts ? : { lowS? : boolean ; prehash? : boolean ; format? : ' compact' | ' der' }
457
- ) => boolean ;
458
- ProjectivePoint: ProjectivePointConstructor ;
459
- Signature: SignatureConstructor ;
460
- utils: {
461
- normPrivateKeyToScalar: (key : PrivKey ) => bigint ;
462
- isValidPrivateKey(key : PrivKey ): boolean ;
463
- randomPrivateKey: () => Uint8Array ;
464
- precompute: (windowSize ? : number , point ? : ProjPointType <bigint >) => ProjPointType <bigint >;
465
- };
466
- };
467
-
468
- // T is usually bigint, but can be something else like complex numbers in BLS curves
469
- interface ProjPointType <T > extends Group <ProjPointType <T >> {
470
- readonly px: T ;
471
- readonly py: T ;
472
- readonly pz: T ;
473
- get x(): bigint ;
474
- get y(): bigint ;
475
- multiply(scalar : bigint ): ProjPointType <T >;
476
- multiplyUnsafe(scalar : bigint ): ProjPointType <T >;
477
- multiplyAndAddUnsafe(Q : ProjPointType <T >, a : bigint , b : bigint ): ProjPointType <T > | undefined ;
478
- toAffine(iz ? : T ): AffinePoint <T >;
479
- isTorsionFree(): boolean ;
480
- clearCofactor(): ProjPointType <T >;
481
- assertValidity(): void ;
482
- hasEvenY(): boolean ;
483
- toRawBytes(isCompressed ? : boolean ): Uint8Array ;
484
- toHex(isCompressed ? : boolean ): string ;
485
- }
486
- // Static methods for 3d XYZ points
487
- interface ProjConstructor <T > extends GroupConstructor <ProjPointType <T >> {
488
- new (x : T , y : T , z : T ): ProjPointType <T >;
489
- fromAffine(p : AffinePoint <T >): ProjPointType <T >;
490
- fromHex(hex : Hex ): ProjPointType <T >;
491
- fromPrivateKey(privateKey : PrivKey ): ProjPointType <T >;
492
- msm(points : ProjPointType [], scalars : bigint []): ProjPointType <T >;
493
- }
494
- ```
495
-
496
- ** ECDSA signatures** are represented by ` Signature ` instances and can be
497
- described by the interface:
498
-
499
- ``` ts
500
- interface SignatureType {
501
- readonly r: bigint ;
502
- readonly s: bigint ;
503
- readonly recovery? : number ;
504
- assertValidity(): void ;
505
- addRecoveryBit(recovery : number ): SignatureType ;
506
- hasHighS(): boolean ;
507
- normalizeS(): SignatureType ;
508
- recoverPublicKey(msgHash : Hex ): ProjPointType <bigint >;
509
- toCompactRawBytes(): Uint8Array ;
510
- toCompactHex(): string ;
511
- // DER-encoded
512
- toDERRawBytes(): Uint8Array ;
513
- toDERHex(): string ;
514
- }
515
- type SignatureConstructor = {
516
- new (r : bigint , s : bigint ): SignatureType ;
517
- fromCompact(hex : Hex ): SignatureType ;
518
- fromDER(hex : Hex ): SignatureType ;
519
- };
520
- ```
400
+ - Are exported as ` ProjectivePoint `
401
+ - Are represented in projective (homogeneous) coordinates: (x, y, z) ∋ (x=x/z, y=y/z)
402
+ - Use complete exception-free formulas for addition and doubling
403
+ - Can be decoded/encoded from/to Uint8Array / hex strings using
404
+ ` ProjectivePoint.fromHex ` and ` ProjectivePoint#toRawBytes() `
405
+ - Have ` assertValidity() ` which checks for being on-curve
406
+ - Have ` toAffine() ` and ` x ` / ` y ` getters which convert to 2d xy affine coordinates
407
+
408
+ ** ECDSA signatures:**
409
+
410
+ - Are represented by ` Signature ` instances with ` r, s ` and optional ` recovery ` properties
411
+ - Have ` recoverPublicKey() ` , ` toCompactRawBytes() ` and ` toDERRawBytes() ` methods
412
+ - Can be prehashed, or non-prehashed:
413
+ - ` sign(msgHash, privKey) ` (default, prehash: false) - you did hashing before
414
+ - ` sign(msg, privKey, {prehash: true}) ` - curves will do hashing for you
415
+ - Are generated deterministically, following [ RFC6979] ( https://www.rfc-editor.org/rfc/rfc6979 ) .
416
+ - Consider [ hedged ECDSA with noise] ( #hedged-ecdsa-with-noise ) for adding randomness into
417
+ for signatures, to get improved security against fault attacks.
521
418
522
419
More examples:
523
420
@@ -581,101 +478,41 @@ const ed25519 = twistedEdwards({
581
478
} as const );
582
479
```
583
480
584
- Twisted Edwards curve's formula is ` ax² + y² = 1 + dx²y² ` . You must specify ` a ` , ` d ` , field ` Fp ` , order ` n ` , cofactor ` h `
481
+ Twisted Edwards curve's formula is ` ax² + y² = 1 + dx²y² ` .
482
+ You must specify ` a ` , ` d ` , field ` Fp ` , order ` n ` , cofactor ` h `
585
483
and coordinates ` Gx ` , ` Gy ` of generator point.
586
-
587
- For EdDSA signatures, ` hash ` param required. ` adjustScalarBytes ` which instructs how to change private scalars could be specified.
588
-
589
- We support [ non-repudiation] ( https://eprint.iacr.org/2020/1244 ) , which help in following scenarios:
590
-
591
- - Contract Signing: if A signed an agreement with B using key that allows repudiation, it can later claim that it signed a different contract
592
- - E-voting: malicious voters may pick keys that allow repudiation in order to deny results
593
- - Blockchains: transaction of amount X might also be valid for a different amount Y
484
+ For EdDSA signatures, ` hash ` param required.
485
+ ` adjustScalarBytes ` which instructs how to change private scalars could be specified.
594
486
595
487
** Edwards points:**
596
488
597
- 1 . Exported as ` ExtendedPoint `
598
- 2 . Represented in extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z)
599
- 3 . Use complete exception-free formulas for addition and doubling
600
- 4 . Can be decoded/encoded from/to Uint8Array / hex strings using ` ExtendedPoint.fromHex ` and ` ExtendedPoint#toRawBytes() `
601
- 5 . Have ` assertValidity() ` which checks for being on-curve
602
- 6 . Have ` toAffine() ` and ` x ` / ` y ` getters which convert to 2d xy affine coordinates
603
- 7 . Have ` isTorsionFree() ` , ` clearCofactor() ` and ` isSmallOrder() ` utilities to handle torsions
489
+ - Are exported as ` ExtendedPoint `
490
+ - Are represented in extended coordinates: (x, y, z, t) ∋ (x=x/z, y=y/z)
491
+ - Use complete exception-free formulas for addition and doubling
492
+ - Can be decoded/encoded from/to Uint8Array / hex strings using ` ExtendedPoint.fromHex ` and ` ExtendedPoint#toRawBytes() `
493
+ - Have ` assertValidity() ` which checks for being on-curve
494
+ - Have ` toAffine() ` and ` x ` / ` y ` getters which convert to 2d xy affine coordinates
495
+ - Have ` isTorsionFree() ` , ` clearCofactor() ` and ` isSmallOrder() ` utilities to handle torsions
604
496
605
- ``` ts
606
- // `twistedEdwards()` returns `CurveFn` of following type:
607
- type CurveFn = {
608
- CURVE: ReturnType <typeof validateOpts >;
609
- getPublicKey: (privateKey : Hex ) => Uint8Array ;
610
- sign: (message : Hex , privateKey : Hex , context ? : Hex ) => Uint8Array ;
611
- verify: (sig : SigType , message : Hex , publicKey : Hex , context ? : Hex ) => boolean ;
612
- ExtendedPoint: ExtPointConstructor ;
613
- utils: {
614
- randomPrivateKey: () => Uint8Array ;
615
- getExtendedPublicKey: (key : PrivKey ) => {
616
- head: Uint8Array ;
617
- prefix: Uint8Array ;
618
- scalar: bigint ;
619
- point: PointType ;
620
- pointBytes: Uint8Array ;
621
- };
622
- };
623
- };
497
+ ** EdDSA signatures:**
624
498
625
- interface ExtPointType extends Group <ExtPointType > {
626
- readonly ex: bigint ;
627
- readonly ey: bigint ;
628
- readonly ez: bigint ;
629
- readonly et: bigint ;
630
- get x(): bigint ;
631
- get y(): bigint ;
632
- assertValidity(): void ;
633
- multiply(scalar : bigint ): ExtPointType ;
634
- multiplyUnsafe(scalar : bigint ): ExtPointType ;
635
- isSmallOrder(): boolean ;
636
- isTorsionFree(): boolean ;
637
- clearCofactor(): ExtPointType ;
638
- toAffine(iz ? : bigint ): AffinePoint <bigint >;
639
- toRawBytes(isCompressed ? : boolean ): Uint8Array ;
640
- toHex(isCompressed ? : boolean ): string ;
641
- }
642
- // Static methods of Extended Point with coordinates in X, Y, Z, T
643
- interface ExtPointConstructor extends GroupConstructor <ExtPointType > {
644
- new (x : bigint , y : bigint , z : bigint , t : bigint ): ExtPointType ;
645
- fromAffine(p : AffinePoint <bigint >): ExtPointType ;
646
- fromHex(hex : Hex ): ExtPointType ;
647
- fromPrivateKey(privateKey : Hex ): ExtPointType ;
648
- msm(points : ExtPointType [], scalars : bigint []): ExtPointType ;
649
- }
650
- ```
651
-
652
- ### montgomery: Montgomery curve
499
+ - ` zip215: true ` is default behavior. It has slightly looser verification logic
500
+ to be [ consensus-friendly] ( https://hdevalence.ca/blog/2020-10-04-its-25519am ) , following [ ZIP215] ( https://zips.z.cash/zip-0215 ) rules
501
+ - ` zip215: false ` switches verification criteria to strict
502
+ [ RFC8032] ( https://www.rfc-editor.org/rfc/rfc8032 ) / [ FIPS 186-5] ( https://csrc.nist.gov/publications/detail/fips/186/5/final )
503
+ and additionally provides [ non-repudiation with SBS] ( https://eprint.iacr.org/2020/1244 ) ,
504
+ which is useful for:
505
+ - Contract Signing: if A signed an agreement with B using key that allows repudiation, it can later claim that it signed a different contract
506
+ - E-voting: malicious voters may pick keys that allow repudiation in order to deny results
507
+ - Blockchains: transaction of amount X might also be valid for a different amount Y
653
508
654
- ``` typescript
655
- import { montgomery } from ' @noble/curves/abstract/montgomery' ;
656
- import { Field } from ' @noble/curves/abstract/modular' ;
509
+ Both modes have SUF-CMA (strong unforgeability under chosen message attacks).
657
510
658
- const x25519 = montgomery ({
659
- a: 486662n ,
660
- Gu: 9n ,
661
- P: 2n ** 255n - 19n ,
662
- montgomeryBits: 255 ,
663
- nByteLength: 32 ,
664
- // Optional param
665
- adjustScalarBytes(bytes ) {
666
- bytes [0 ] &= 248 ;
667
- bytes [31 ] &= 127 ;
668
- bytes [31 ] |= 64 ;
669
- return bytes ;
670
- },
671
- });
672
- ```
511
+ ### montgomery: Montgomery curve
673
512
674
513
The module contains methods for x-only ECDH on Curve25519 / Curve448 from RFC7748.
675
514
Proper Elliptic Curve Points are not implemented yet.
676
515
677
- You must specify curve params ` Fp ` , ` a ` , ` Gu ` coordinate of u, ` montgomeryBits ` and ` nByteLength ` .
678
-
679
516
### bls: Barreto-Lynn-Scott curves
680
517
681
518
The module abstracts BLS (Barreto-Lynn-Scott) pairing-friendly elliptic curve construction.
0 commit comments