Skip to content

Commit 5c991ea

Browse files
committed
readme
1 parent 134bd3d commit 5c991ea

File tree

1 file changed

+60
-223
lines changed

1 file changed

+60
-223
lines changed

README.md

+60-223
Original file line numberDiff line numberDiff line change
@@ -145,18 +145,17 @@ const pub = ed25519.getPublicKey(priv);
145145
const msg = new TextEncoder().encode('hello');
146146
const sig = ed25519.sign(msg, priv);
147147
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
149149

150150
// Variants from RFC8032: with context, prehashed
151151
import { ed25519ctx, ed25519ph } from '@noble/curves/ed25519';
152152
```
153153

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.
156156
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).
160159

161160
X25519 follows [RFC7748](https://www.rfc-editor.org/rfc/rfc7748).
162161

@@ -353,171 +352,69 @@ method: check out examples.
353352

354353
```ts
355354
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';
360359

361360
const hmacSha256 = (key: Uint8Array, ...msgs: Uint8Array[]) =>
362361
hmac(sha256, key, concatBytes(...msgs));
363362

364-
// secq256k1: cycle of secp256k1 with Fp/N flipped.
363+
// secQ (not secP) - secq256k1 is a cycle of secp256k1 with Fp/N flipped.
365364
// https://personaelabs.org/posts/spartan-ecdsa
366365
// https://zcash.github.io/halo2/background/curves.html#cycles-of-curves
367366
const secq256k1 = weierstrass({
368-
// Curve equation params a, b
369367
a: 0n,
370368
b: 7n,
371-
// Field over which we'll do calculations
372369
Fp: Field(2n ** 256n - 432420386565659656852420866394968145599n),
373-
// Curve order, total count of valid points in the field.
374370
n: 2n ** 256n - 2n ** 32n - 2n ** 9n - 2n ** 8n - 2n ** 7n - 2n ** 6n - 2n ** 4n - 1n,
375-
// Base point (x, y) aka generator point
376371
Gx: 55066263022277343669578718895168534326250603453777594175500187360389116729240n,
377372
Gy: 32670510020758816978083085130507043184471273380659243275938904335757337482424n,
378-
379373
hash: sha256,
380374
hmac: hmacSha256,
381375
randomBytes,
382376
});
383377

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
385380
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,
393387
hash: sha256,
394388
hmac: hmacSha256,
395389
randomBytes,
396390
});
397-
398-
// Replace weierstrass() with weierstrassPoints() if you don't need ECDSA, hash, hmac, randomBytes
399391
```
400392

401393
Short Weierstrass curve's formula is `y² = x³ + ax + b`. `weierstrass`
402394
expects arguments `a`, `b`, field `Fp`, curve order `n`, cofactor `h`
403395
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.
432397

433398
**Weierstrass points:**
434399

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.
521418

522419
More examples:
523420

@@ -581,101 +478,41 @@ const ed25519 = twistedEdwards({
581478
} as const);
582479
```
583480

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`
585483
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.
594486

595487
**Edwards points:**
596488

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
604496

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:**
624498

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
653508

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).
657510

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
673512

674513
The module contains methods for x-only ECDH on Curve25519 / Curve448 from RFC7748.
675514
Proper Elliptic Curve Points are not implemented yet.
676515

677-
You must specify curve params `Fp`, `a`, `Gu` coordinate of u, `montgomeryBits` and `nByteLength`.
678-
679516
### bls: Barreto-Lynn-Scott curves
680517

681518
The module abstracts BLS (Barreto-Lynn-Scott) pairing-friendly elliptic curve construction.

0 commit comments

Comments
 (0)