@pact-toolbox/signers
Version:
135 lines (129 loc) • 5.74 kB
JavaScript
import { TextEncoder, base16, base64Url, blake2b, createKeyPairFromBytes, createKeyPairFromPrivateKeyBytes, exportBase16Key, generateKeyPair, signBytes, utf8 } from "@pact-toolbox/crypto";
//#region src/command-signer.ts
/** Checks whether the provided value implements the {@link PactCommandSigner} interface. */
function isPactCommandSigner(value) {
return "signPactCommands" in value && typeof value.signPactCommands === "function";
}
/** Asserts that the provided value implements the {@link PactCommandSigner} interface. */
function assertIsPactCommandSigner(value) {
if (!isPactCommandSigner(value)) throw new Error("Value is not a PactCommandSigner");
}
async function partiallySignPactCommand(keyPairs, command) {
const cmd = JSON.stringify(command);
const cmdBytes = utf8.encode(cmd);
const hash = blake2b(cmdBytes, void 0, 32);
const keyPairMap = /* @__PURE__ */ new Map();
for (const keyPair of keyPairs) {
const pubKeyHex = await exportBase16Key(keyPair.publicKey);
keyPairMap.set(pubKeyHex, keyPair);
}
const sigs = [];
for (const signer of command.signers) {
const pubKey = signer.pubKey;
const keyPair = keyPairMap.get(pubKey);
if (!keyPair) {
sigs.push({ pubKey });
continue;
}
const signatureBytes = await signBytes(keyPair.privateKey, hash);
const signatureHex = base16.decode(signatureBytes);
sigs.push({
pubKey,
sig: signatureHex
});
}
return {
cmd,
hash,
sigs
};
}
function isTransactionFullSig(sig) {
return "sig" in sig && sig.sig !== void 0;
}
function isFullySignedTransaction(transaction) {
return typeof transaction === "object" && transaction !== null && "cmd" in transaction && "hash" in transaction && "sigs" in transaction && Array.isArray(transaction.sigs) && transaction.sigs.every(isTransactionFullSig);
}
function finalizeTransaction(transaction) {
return Object.freeze({
cmd: transaction.cmd,
hash: typeof transaction.hash !== "string" && transaction.hash instanceof Uint8Array ? base64Url.decode(transaction.hash) : transaction.hash,
sigs: transaction.sigs.filter((sig) => "sig" in sig)
});
}
//#endregion
//#region src/message-signer.ts
/** Checks whether the provided value implements the {@link MessageSigner} interface. */
function isMessageSigner(value) {
return "signMessages" in value && typeof value.signMessages === "function";
}
/** Asserts that the provided value implements the {@link MessageSigner} interface. */
function assertIsMessageSigner(value) {
if (!isMessageSigner(value)) throw new Error("Value is not a MessageSigner");
}
//#endregion
//#region src/keypair-signer.ts
/** Checks whether the provided value implements the {@link KeyPairSigner} interface. */
function isKeyPairSigner(value) {
return "keyPair" in value && typeof value.keyPair === "object" && isMessageSigner(value) && isPactCommandSigner(value);
}
/** Asserts that the provided value implements the {@link KeyPairSigner} interface. */
function assertIsKeyPairSigner(value) {
if (!isKeyPairSigner(value)) throw new Error("Value is not a KeyPairSigner");
}
/** Creates a KeyPairSigner from the provided Crypto KeyPair. */
async function createSignerFromKeyPair(keyPair) {
const address = await exportBase16Key(keyPair.publicKey);
const out = {
address,
keyPair,
signMessages: (messages) => {
return Promise.all(messages.map(async (message) => Object.freeze({ [address]: await signBytes(keyPair.privateKey, message.content) })));
},
signPactCommands: (commands) => {
return Promise.all(commands.map((cmd) => partiallySignPactCommand([keyPair], cmd)));
}
};
return Object.freeze(out);
}
/** Securely generates a signer capable of signing messages and transactions using a Crypto KeyPair. */
async function generateKeyPairSigner() {
return createSignerFromKeyPair(await generateKeyPair());
}
/** Creates a signer capable of signing messages and transactions using the 64 bytes of a KeyPair. */
async function createKeyPairSignerFromBytes(bytes, extractable) {
return createSignerFromKeyPair(await createKeyPairFromBytes(bytes, extractable));
}
/** Creates a signer capable of signing messages and transactions using the 32 bytes of a private key. */
async function createKeyPairSignerFromPrivateKeyBytes(bytes, extractable) {
return createSignerFromKeyPair(await createKeyPairFromPrivateKeyBytes(bytes, extractable));
}
async function createKeyPairSignerFromBase16PrivateKey(privateKey, extractable) {
return createKeyPairSignerFromPrivateKeyBytes(base16.encode(privateKey), extractable);
}
//#endregion
//#region src/noop.ts
/** Creates a NoopSigner from the provided Address. */
function createNoopSigner(address) {
const out = {
address,
signMessages: (messages) => Promise.resolve(messages.map(() => Object.freeze({}))),
signPactCommands: (commands) => Promise.resolve(commands.map(() => Object.freeze({})))
};
return Object.freeze(out);
}
//#endregion
//#region src/signable-message.ts
/**
* Creates a signable message from a provided content.
* If a string is provided, it will be UTF-8 encoded.
*/
function createSignableMessage(content, signatures = {}) {
return Object.freeze({
content: typeof content === "string" ? new TextEncoder().encode(content) : content,
signatures: Object.freeze({ ...signatures })
});
}
//#endregion
export { assertIsKeyPairSigner, assertIsMessageSigner, assertIsPactCommandSigner, createKeyPairSignerFromBase16PrivateKey, createKeyPairSignerFromBytes, createKeyPairSignerFromPrivateKeyBytes, createNoopSigner, createSignableMessage, createSignerFromKeyPair, finalizeTransaction, generateKeyPairSigner, isFullySignedTransaction, isKeyPairSigner, isMessageSigner, isPactCommandSigner, isTransactionFullSig, partiallySignPactCommand };
//# sourceMappingURL=index.node.mjs.map