Skip to content

Commit c348aad

Browse files
committed
Improve readme
1 parent dd997c8 commit c348aad

File tree

1 file changed

+66
-47
lines changed

1 file changed

+66
-47
lines changed

README.md

Lines changed: 66 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -94,81 +94,100 @@ type Hex = Uint8Array | string;
9494
### getPublicKey
9595

9696
```ts
97-
function getPublicKey(privateKey: Hex, isCompressed?: boolean): Uint8Array;
97+
import { getPublicKey, utils, ProjectivePoint } from '@noble/secp256k1';
98+
const privKey = utils.randomPrivateKey();
99+
const pubKey33b = getPublicKey(privKey);
100+
const pubKey65b = getPublicKey(privKey, false);
101+
const pubKeyPoint = ProjectivePoint.fromPrivateKey(privKey);
102+
const samePoint = ProjectivePoint.fromHex(pubKeyPoint.toHex());
98103
```
99104

100-
Generates 33-byte compressed public key from 32-byte private key.
101-
102-
- If you need uncompressed 65-byte public key, set second argument to `false`.
103-
- Use `ProjectivePoint.fromPrivateKey(privateKey)` for Point instance.
104-
- Use `ProjectivePoint.fromHex(publicKey)` to convert Hex / Uint8Array into Point.
105+
Generates 33-byte compressed (default) or 65-byte public key from 32-byte private key.
105106

106107
### sign
107108

108109
```ts
109-
function sign(
110-
messageHash: Hex, // message hash (not message) which would be signed
111-
privateKey: Hex, // private key which will sign the hash
112-
opts?: { lowS: boolean; extraEntropy: boolean | Hex } // optional params
113-
): Signature;
114-
function signAsync(
115-
messageHash: Hex,
116-
privateKey: Hex,
117-
opts?: { lowS: boolean; extraEntropy: boolean | Hex }
118-
): Promise<Signature>;
119-
120-
sign(msgHash, privKey, { lowS: false }); // Malleable signature
121-
sign(msgHash, privKey, { extraEntropy: true }); // Improved security
110+
import * as secp from '@noble/secp256k1';
111+
import { sha256 } from '@noble/hashes/sha256';
112+
import { utf8ToBytes } from '@noble/hashes/utils';
113+
const msg = 'noble cryptography';
114+
const msgHash = sha256(utf8ToBytes(msg));
115+
const priv = secp.utils.randomPrivateKey();
116+
const sigA = secp.sign(msgHash, priv);
117+
118+
// Variants
119+
const sigB = await secp.signAsync(msgHash, priv);
120+
const sigC = secp.sign(msgHash, priv, { extraEntropy: true }); // hedged sig
121+
const sigC2 = secp.sign(msgHash, priv, { extraEntropy: Uint8Array.from([0xca, 0xfe]) });
122+
const sigD = secp.sign(msgHash, priv, { lowS: false }); // malleable sig
122123
```
123124

124-
Generates low-s deterministic-k RFC6979 ECDSA signature. Assumes hash of message,
125+
Generates low-s deterministic-k RFC6979 ECDSA signature. Requries hash of message,
125126
which means you'll need to do something like `sha256(message)` before signing.
126127

127-
1. `lowS: false` allows to create malleable signatures, for compatibility with openssl.
128-
Default `lowS: true` prohibits signatures which have (sig.s >= CURVE.n/2n) and is compatible with BTC/ETH.
129-
2. `extraEntropy: true` enables hedged signatures with improved protection against fault attacks
130-
- Check out blog post
131-
[Deterministic signatures are not your friends](https://paulmillr.com/posts/deterministic-signatures/)
132-
and [spec draft](https://datatracker.ietf.org/doc/draft-irtf-cfrg-det-sigs-with-noise/)
133-
- Follows section 3.6 of RFC6979:
134-
- No disadvantage: if an entropy generator is broken, sigs would be the same
135-
as they are without the option
128+
`extraEntropy: true` enables hedged signatures. They incorporate
129+
extra randomness into RFC6979 (described in section 3.6),
130+
to provide additional protection against fault attacks.
131+
Check out blog post [Deterministic signatures are not your friends](https://paulmillr.com/posts/deterministic-signatures/).
132+
Even if their RNG is broken, they will fall back to determinism.
133+
134+
Default behavior `lowS: true` prohibits signatures which have (sig.s >= CURVE.n/2n) and is compatible with BTC/ETH.
135+
Setting `lowS: false` allows to create malleable signatures, which is default openssl behavior.
136+
Non-malleable signatures can still be successfully verified in openssl.
136137

137138
### verify
138139

139140
```ts
140-
function verify(
141-
signature: Hex | Signature, // returned by the `sign` function
142-
messageHash: Hex, // message hash (not message) that must be verified
143-
publicKey: Hex, // public (not private) key
144-
opts?: { lowS: boolean } // optional params; { lowS: true } by default
145-
): boolean;
141+
import * as secp from '@noble/secp256k1';
142+
const hex = secp.etc.hexToBytes;
143+
const sig = hex(
144+
'ddc633c5b48a1a6725c31201892715dda3058350f7b444e89d32c33c90d9c9e218d7eaf02c2254e88c3b33d755394b08bcc7efd13df02338510b750b64572983'
145+
);
146+
const msgHash = hex('736403f76264eccc1b77ba58dc8fc690e76b2b1532ba82c736a60f3862082db3');
147+
// const priv = 'd60937c2a1ece169888d4c48717dfcc0e1a7af915505823148cca11859210e9c';
148+
const pubKey = hex('020b6d70b68873ff8fd729adf5cf4bf45021b34236f991768249cba06b11136ec6');
149+
150+
const isValid = secp.verify(sig, msgHash, pubKey);
151+
152+
// Variants
153+
const isValidLoose = secp.verify(sig, msgHash, pubKey, { lowS: false });
146154
```
147155

148-
Verifies ECDSA signature and ensures it has lowS (compatible with BTC/ETH).
149-
`lowS: false` turns off malleability check, but makes it OpenSSL-compatible.
156+
Verifies ECDSA signature.
157+
Default behavior `lowS: true` prohibits malleable signatures which have (`sig.s >= CURVE.n/2n`) and
158+
is compatible with BTC / ETH.
159+
Setting `lowS: false` allows to create signatures, which is default openssl behavior.
150160

151161
### getSharedSecret
152162

153163
```ts
154-
function getSharedSecret(
155-
privateKeyA: Uint8Array | string, // Alices's private key
156-
publicKeyB: Uint8Array | string, // Bob's public key
157-
isCompressed = true // optional arg. (default) true=33b key, false=65b.
158-
): Uint8Array;
164+
import * as secp from '@noble/secp256k1';
165+
const bobsPriv = secp.utils.randomPrivateKey();
166+
const alicesPub = secp.getPublicKey(secp.utils.randomPrivateKey());
167+
168+
// ECDH between Alice and Bob
169+
const shared33b = secp.getSharedSecret(bobsPriv, alicesPub);
170+
const shared65b = secp.getSharedSecret(bobsPriv, alicesPub, false);
171+
const sharedPoint = secp.ProjectivePoint.fromHex(alicesPub).multiply(bobsPriv);
159172
```
160173

161174
Computes ECDH (Elliptic Curve Diffie-Hellman) shared secret between
162175
key A and different key B.
163176

164-
Use `ProjectivePoint.fromHex(publicKeyB).multiply(privateKeyA)` for Point instance
165-
166177
### recoverPublicKey
167178

168179
```ts
169-
signature.recoverPublicKey(
170-
msgHash: Uint8Array | string
171-
): Uint8Array | undefined;
180+
import * as secp from '@noble/secp256k1';
181+
182+
import { sha256 } from '@noble/hashes/sha256';
183+
import { utf8ToBytes } from '@noble/hashes/utils';
184+
const msg = 'noble cryptography';
185+
const msgHash = sha256(utf8ToBytes(msg));
186+
const priv = secp.utils.randomPrivateKey();
187+
const pub1 = secp.getPubkicKey(priv);
188+
const sig = secp.sign(msgHash, priv);
189+
190+
const pub2 = sig.recoverPublicKey(msgHash);
172191
```
173192

174193
Recover public key from Signature instance with `recovery` bit set.

0 commit comments

Comments
 (0)