curve-p256
This is a JS implementation of secp256r1
(P-256
) elliptic curve encryption algorithm library, used for ECDH
key exchange & ECDSA
signing. This library is extract from @noble/curves.
- ✍️ ECDSA signatures compliant with RFC6979
- 🤝 Elliptic Curve Diffie-Hellman ECDH
- 🔒 Supports hedged signatures guarding against fault attacks
In addition, I have added support for Wechat Mini Programs. Since @noble/curves depends on the instance methods of Crypto in the Web Crypto API, which are not yet supported by Mini Programs, I have implemented these methods myself.
这是一个 JS 实现的 secp256r1
(P-256
) 椭圆曲线加密算法库,用于 ECDH
密钥交换和 ECDSA
签名。这个库是从@noble/curves 中提取出来的。
另外,我对微信小程序做了支持。由于 @noble/curves 依赖了 Web Crypto API 中 Crypto 的实例方法,但小程序尚未支持,所以我实现了这些方法。
Usage
NPM:
npm i curve-p256
YARN:
yarn add curve-p256
Example:
ECDH: Diffie-Hellman shared secrets
import { p256 } from 'curve-p256';
const privBob = p256.utils.randomPrivateKey();
const pubBob = p256.getPublicKey(privBob);
const privAlice = p256.utils.randomPrivateKey();
const pubAlice = p256.getPublicKey(privAlice);
const shared1 = p256.getSharedSecret(privBob, pubAlice);
const shared2 = p256.getSharedSecret(privAlice, pubBob);
console.log(shared1 === shared2); // true
ECDSA signatures over secp256r1 and others
import { p256 } from 'curve-p256';
const priv = p256.utils.randomPrivateKey();
const pub = p256.getPublicKey(priv); // Convert private key to public.
const msg = new TextEncoder().encode('Hello world!');
const sig = p256.sign(msg, priv); // Sign msg with private key.
const isValid = p256.verify(sig, msg, pub);
console.log(isValid); // true
Public key recovery
import { p256 } from 'curve-p256';
const priv = p256.utils.randomPrivateKey();
const pub = p256.getPublicKey(priv);
const msg = new TextEncoder().encode('Hello world!');
const sig = p256.sign(msg, priv); // `{prehash: true}` option is available
const pub2 = sig.recoverPublicKey(msg).toRawBytes(); // public key recovery
console.log(pub === pub2); // true
Utils
import { bytesToHex, hexToBytes, concatBytes } from 'curve-p256';
// hex = 'deadbeef'
const hex = bytesToHex(Uint8Array.from([0xde, 0xad, 0xbe, 0xef]));
// bytes = Uint8Array.from([0xde, 0xad, 0xbe, 0xef])
const bytes = hexToBytes('deadbeef');
// bytes = Uint8Array.from([0xde, 0xad, 0xbe, 0xef])
const concated = concatBytes(Uint8Array.from([0xde, 0xad]), Uint8Array.from([0xbe, 0xef]));
Speed
Benchmark results on Apple M2 with node v20:
p256
init x 38 ops/sec @ 26ms/op
getPublicKey x 6,530 ops/sec @ 153μs/op
sign x 5,074 ops/sec @ 197μs/op
verify x 626 ops/sec @ 1ms/op
ecdh
p256 x 511 ops/sec @ 1ms/op