| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- /**
- * Add details about signing here.
- *
- * @_subsection: api/crypto:Signing [about-signing]
- */
- import { secp256k1 } from "@noble/curves/secp256k1";
- import { concat, dataLength, getBytes, getBytesCopy, hexlify, toBeHex, assertArgument } from "../utils/index.js";
- import { Signature } from "./signature.js";
- /**
- * A **SigningKey** provides high-level access to the elliptic curve
- * cryptography (ECC) operations and key management.
- */
- export class SigningKey {
- #privateKey;
- /**
- * Creates a new **SigningKey** for %%privateKey%%.
- */
- constructor(privateKey) {
- assertArgument(dataLength(privateKey) === 32, "invalid private key", "privateKey", "[REDACTED]");
- this.#privateKey = hexlify(privateKey);
- }
- /**
- * The private key.
- */
- get privateKey() { return this.#privateKey; }
- /**
- * The uncompressed public key.
- *
- * This will always begin with the prefix ``0x04`` and be 132
- * characters long (the ``0x`` prefix and 130 hexadecimal nibbles).
- */
- get publicKey() { return SigningKey.computePublicKey(this.#privateKey); }
- /**
- * The compressed public key.
- *
- * This will always begin with either the prefix ``0x02`` or ``0x03``
- * and be 68 characters long (the ``0x`` prefix and 33 hexadecimal
- * nibbles)
- */
- get compressedPublicKey() { return SigningKey.computePublicKey(this.#privateKey, true); }
- /**
- * Return the signature of the signed %%digest%%.
- */
- sign(digest) {
- assertArgument(dataLength(digest) === 32, "invalid digest length", "digest", digest);
- const sig = secp256k1.sign(getBytesCopy(digest), getBytesCopy(this.#privateKey), {
- lowS: true
- });
- return Signature.from({
- r: toBeHex(sig.r, 32),
- s: toBeHex(sig.s, 32),
- v: (sig.recovery ? 0x1c : 0x1b)
- });
- }
- /**
- * Returns the [[link-wiki-ecdh]] shared secret between this
- * private key and the %%other%% key.
- *
- * The %%other%% key may be any type of key, a raw public key,
- * a compressed/uncompressed pubic key or aprivate key.
- *
- * Best practice is usually to use a cryptographic hash on the
- * returned value before using it as a symetric secret.
- *
- * @example:
- * sign1 = new SigningKey(id("some-secret-1"))
- * sign2 = new SigningKey(id("some-secret-2"))
- *
- * // Notice that privA.computeSharedSecret(pubB)...
- * sign1.computeSharedSecret(sign2.publicKey)
- * //_result:
- *
- * // ...is equal to privB.computeSharedSecret(pubA).
- * sign2.computeSharedSecret(sign1.publicKey)
- * //_result:
- */
- computeSharedSecret(other) {
- const pubKey = SigningKey.computePublicKey(other);
- return hexlify(secp256k1.getSharedSecret(getBytesCopy(this.#privateKey), getBytes(pubKey), false));
- }
- /**
- * Compute the public key for %%key%%, optionally %%compressed%%.
- *
- * The %%key%% may be any type of key, a raw public key, a
- * compressed/uncompressed public key or private key.
- *
- * @example:
- * sign = new SigningKey(id("some-secret"));
- *
- * // Compute the uncompressed public key for a private key
- * SigningKey.computePublicKey(sign.privateKey)
- * //_result:
- *
- * // Compute the compressed public key for a private key
- * SigningKey.computePublicKey(sign.privateKey, true)
- * //_result:
- *
- * // Compute the uncompressed public key
- * SigningKey.computePublicKey(sign.publicKey, false);
- * //_result:
- *
- * // Compute the Compressed a public key
- * SigningKey.computePublicKey(sign.publicKey, true);
- * //_result:
- */
- static computePublicKey(key, compressed) {
- let bytes = getBytes(key, "key");
- // private key
- if (bytes.length === 32) {
- const pubKey = secp256k1.getPublicKey(bytes, !!compressed);
- return hexlify(pubKey);
- }
- // raw public key; use uncompressed key with 0x04 prefix
- if (bytes.length === 64) {
- const pub = new Uint8Array(65);
- pub[0] = 0x04;
- pub.set(bytes, 1);
- bytes = pub;
- }
- const point = secp256k1.ProjectivePoint.fromHex(bytes);
- return hexlify(point.toRawBytes(compressed));
- }
- /**
- * Returns the public key for the private key which produced the
- * %%signature%% for the given %%digest%%.
- *
- * @example:
- * key = new SigningKey(id("some-secret"))
- * digest = id("hello world")
- * sig = key.sign(digest)
- *
- * // Notice the signer public key...
- * key.publicKey
- * //_result:
- *
- * // ...is equal to the recovered public key
- * SigningKey.recoverPublicKey(digest, sig)
- * //_result:
- *
- */
- static recoverPublicKey(digest, signature) {
- assertArgument(dataLength(digest) === 32, "invalid digest length", "digest", digest);
- const sig = Signature.from(signature);
- let secpSig = secp256k1.Signature.fromCompact(getBytesCopy(concat([sig.r, sig.s])));
- secpSig = secpSig.addRecoveryBit(sig.yParity);
- const pubKey = secpSig.recoverPublicKey(getBytesCopy(digest));
- assertArgument(pubKey != null, "invalid signautre for digest", "signature", signature);
- return "0x" + pubKey.toHex(false);
- }
- /**
- * Returns the point resulting from adding the ellipic curve points
- * %%p0%% and %%p1%%.
- *
- * This is not a common function most developers should require, but
- * can be useful for certain privacy-specific techniques.
- *
- * For example, it is used by [[HDNodeWallet]] to compute child
- * addresses from parent public keys and chain codes.
- */
- static addPoints(p0, p1, compressed) {
- const pub0 = secp256k1.ProjectivePoint.fromHex(SigningKey.computePublicKey(p0).substring(2));
- const pub1 = secp256k1.ProjectivePoint.fromHex(SigningKey.computePublicKey(p1).substring(2));
- return "0x" + pub0.add(pub1).toHex(!!compressed);
- }
- }
- //# sourceMappingURL=signing-key.js.map
|