@swtc/keypairs
Version:
swtc keypairs
333 lines • 15.5 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Factory = Factory;
const brorand_1 = __importDefault(require("brorand"));
const hash_js_1 = __importDefault(require("hash.js"));
const elliptic_1 = require("elliptic");
const sm_js_1 = require("@swtc/sm.js");
const bn_js_1 = __importDefault(require("bn.js"));
const address_codec_1 = require("@swtc/address-codec");
const common_1 = require("@swtc/common");
const secp256k1_1 = require("./secp256k1");
const sm2p256v1_1 = require("./sm2p256v1");
const utils_1 = require("./utils");
const Ed25519 = (0, elliptic_1.eddsa)("ed25519");
const Secp256k1 = (0, elliptic_1.ec)("secp256k1");
// const Secp256k1Gm = sm2
function hashOpen(message) {
return hash_js_1.default.sha512().update(message).digest().slice(0, 32);
}
function hashGm(message) {
return new common_1.SM3().update(message).digest().slice(0, 32);
}
function Factory(chain_or_token = "jingtum") {
const addressCodec = (0, address_codec_1.Factory)(chain_or_token);
const guomi = addressCodec.guomi;
const token = addressCodec.token;
const hash = guomi ? hashGm : hashOpen;
const secp256k1 = {
deriveKeypair: (entropy, options = {}) => {
const prefix = "00";
const privateKey = prefix +
(0, secp256k1_1.derivePrivateKey)(entropy, options).toString(16, 64).toUpperCase();
const publicKey = (0, common_1.funcBytesToHex)(Secp256k1.keyFromPrivate(privateKey.slice(2))
.getPublic()
.encodeCompressed());
return { privateKey, publicKey };
},
deriveKeypairWithPrivateKey: (rawPrivateKey) => {
const prefix = "00";
const privateKey = prefix + rawPrivateKey.toUpperCase();
const publicKey = (0, common_1.funcBytesToHex)(Secp256k1.keyFromPrivate(privateKey.slice(2))
.getPublic()
.encodeCompressed());
return { privateKey, publicKey };
},
sign: (message, privateKey) => {
return (0, common_1.funcBytesToHex)(Secp256k1.sign(hash(message), (0, common_1.funcHexToBytes)(privateKey), {
canonical: true
}).toDER());
},
verify: (message, signature, publicKey) => {
return Secp256k1.verify(hash(message), signature, (0, common_1.funcHexToBytes)(publicKey));
},
signTx: (message, privateKey) => {
return (0, common_1.funcBytesToHex)(Secp256k1.sign(message, (0, common_1.funcHexToBytes)(privateKey), {
canonical: true
}).toDER());
},
verifyTx: (message, signature, publicKey) => {
return Secp256k1.verify(message, signature, (0, common_1.funcHexToBytes)(publicKey));
}
};
const sm2p256v1 = {
deriveKeypair: (entropy, options = {}) => {
const prefix = "00";
const pri = (0, sm2p256v1_1.derivePrivateKey)(entropy, options);
const privateKey = prefix + pri.toString(16, 64).toUpperCase();
const publicKey = (0, common_1.funcBytesToHex)(sm_js_1.sm2.SM2KeyPair(null, pri).pub.encodeCompressed());
return { privateKey, publicKey };
},
deriveKeypairWithPrivateKey: (rawPrivateKey) => {
const prefix = "00";
const pri = new bn_js_1.default(rawPrivateKey, "hex");
const privateKey = prefix + rawPrivateKey.toUpperCase();
const publicKey = (0, common_1.funcBytesToHex)(sm_js_1.sm2.SM2KeyPair(null, pri).pub.encodeCompressed());
return { privateKey, publicKey };
},
sign: (message, privateKey) => {
const keypair = sm_js_1.sm2.SM2KeyPair(null, new bn_js_1.default(privateKey, "hex"));
return (0, common_1.funcBytesToHex)(new sm_js_1.Signature(keypair.sign(hash(message))).toDER());
},
verify: (message, signature, publicKey) => {
const keypair = sm_js_1.sm2.SM2KeyPair(publicKey);
const sig = new sm_js_1.Signature(signature, "hex");
return keypair.verify(hash(message), sig.r, sig.s);
},
signTx: (message, privateKey) => {
if (typeof message === "string" && /^[0-9A-F]{16}/i.test(message)) {
// if in hex format
message = (0, common_1.funcHexToBytes)(message);
}
const keypair = sm_js_1.sm2.SM2KeyPair(null, new bn_js_1.default(privateKey, "hex"));
return (0, common_1.funcBytesToHex)(new sm_js_1.Signature(keypair.sign(message)).toDER());
// return this.sign(message, privateKey)
},
verifyTx: (message, signature, publicKey) => {
if (typeof message === "string" && /^[0-9A-F]{16}/i.test(message)) {
// if in hex format
message = (0, common_1.funcHexToBytes)(message);
}
// if (typeof signature === "string" && /^[0-9A-F]{16}/i.test(signature)) {
// // if in hex format
// signature = hexToBytes(signature)
// }
const keypair = sm_js_1.sm2.SM2KeyPair(publicKey);
const sig = new sm_js_1.Signature(signature, "hex");
return keypair.verify(hash(message), sig.r, sig.s);
}
};
const ed25519 = {
deriveKeypair: (entropy) => {
const prefix = "ED";
const rawPrivateKey = hash(entropy);
const privateKey = prefix + (0, common_1.funcBytesToHex)(rawPrivateKey);
const publicKey = prefix + (0, common_1.funcBytesToHex)(Ed25519.keyFromSecret(rawPrivateKey).pubBytes());
return { privateKey, publicKey };
},
deriveKeypairWithPrivateKey: (rawPrivateKey) => {
const prefix = "ED";
const privateKey = prefix + rawPrivateKey.toUpperCase();
const publicKey = prefix +
(0, common_1.funcBytesToHex)(Ed25519.keyFromSecret((0, common_1.funcHexToBytes)(rawPrivateKey)).pubBytes());
return { privateKey, publicKey };
},
sign: (message, privateKey) => {
// caution: Ed25519.sign interprets all strings as hex, stripping
// any non-hex characters without warning
(0, common_1.funcAssert)(Array.isArray(message), "message must be array of octets");
return (0, common_1.funcBytesToHex)(Ed25519.sign(message, (0, common_1.funcHexToBytes)(privateKey).slice(1)).toBytes());
},
verify: (message, signature, publicKey) => {
return Ed25519.verify(message, (0, common_1.funcHexToBytes)(signature), (0, common_1.funcHexToBytes)(publicKey).slice(1));
},
signTx: (message, privateKey) => {
// caution: Ed25519.sign interprets all strings as hex, stripping
// any non-hex characters without warning
return Ed25519.sign(message, (0, common_1.funcHexToBytes)(privateKey).slice(1)).toHex();
},
verifyTx: (message, signature, publicKey) => {
return Ed25519.verify(message, (0, common_1.funcHexToBytes)(signature), (0, common_1.funcHexToBytes)(publicKey).slice(1));
}
};
const ed25519guomi = {
deriveKeypair: (entropy) => {
const prefix = "ED";
const rawPrivateKey = hash(entropy);
const privateKey = prefix + (0, common_1.funcBytesToHex)(rawPrivateKey);
const publicKey = prefix + (0, common_1.funcBytesToHex)(Ed25519.keyFromSecret(rawPrivateKey).pubBytes());
return { privateKey, publicKey };
},
deriveKeypairWithPrivateKey: (rawPrivateKey) => {
const prefix = "ED";
const privateKey = prefix + rawPrivateKey.toUpperCase();
const publicKey = prefix +
(0, common_1.funcBytesToHex)(Ed25519.keyFromSecret((0, common_1.funcHexToBytes)(rawPrivateKey)).pubBytes());
return { privateKey, publicKey };
},
sign: (message, privateKey) => {
// caution: Ed25519.sign interprets all strings as hex, stripping
// any non-hex characters without warning
(0, common_1.funcAssert)(Array.isArray(message), "message must be array of octets");
return (0, common_1.funcBytesToHex)(Ed25519.sign(message, (0, common_1.funcHexToBytes)(privateKey).slice(1)).toBytes());
},
verify: (message, signature, publicKey) => {
return Ed25519.verify(message, (0, common_1.funcHexToBytes)(signature), (0, common_1.funcHexToBytes)(publicKey).slice(1));
},
signTx: (message, privateKey) => {
// caution: Ed25519.sign interprets all strings as hex, stripping
// any non-hex characters without warning
return Ed25519.sign(message, (0, common_1.funcHexToBytes)(privateKey).slice(1)).toHex();
},
verifyTx: (message, signature, publicKey) => {
return Ed25519.verify(message, (0, common_1.funcHexToBytes)(signature), (0, common_1.funcHexToBytes)(publicKey).slice(1));
}
};
function generateSeed(options = {}) {
(0, common_1.funcAssert)(!options.entropy || options.entropy.length >= 16, "entropy too short");
const entropy = options.entropy ? options.entropy.slice(0, 16) : (0, brorand_1.default)(16);
const type = options.algorithm === "ed25519"
? "ed25519"
: guomi
? "sm2p256v1"
: "secp256k1";
return addressCodec.encodeSeed(entropy, type);
}
function select(algorithm) {
const methods = {
secp256k1,
sm2p256v1,
ed25519,
ed25519guomi
};
// return guomi ? methods[`${algorithm}guomi`] : methods[algorithm]
return algorithm === "ed25519"
? guomi
? methods.ed25519guomi
: methods.ed25519
: methods[algorithm];
}
function getAlgorithmFromKey(key) {
const bytes = (0, common_1.funcHexToBytes)(key);
return bytes.length === 33 && bytes[0] === 0xed
? "ed25519"
: guomi
? "sm2p256v1"
: "secp256k1";
}
function sign(messageHex, privateKey) {
const algorithm = getAlgorithmFromKey(privateKey);
return select(algorithm).sign((0, common_1.funcHexToBytes)(messageHex), privateKey);
}
function verify(messageHex, signature, publicKey) {
const algorithm = getAlgorithmFromKey(publicKey);
return select(algorithm).verify((0, common_1.funcHexToBytes)(messageHex), signature, publicKey);
}
function signTx(messageHex, privateKey) {
const algorithm = getAlgorithmFromKey(privateKey);
return select(algorithm).signTx(messageHex, privateKey);
}
function verifyTx(messageHex, signature, publicKey) {
const algorithm = getAlgorithmFromKey(publicKey);
return select(algorithm).verifyTx(messageHex, signature, publicKey);
}
function deriveKeypair(secret_or_private_key, algorithm = guomi ? "sm2p256v1" : "secp256k1") {
const secret = secret_or_private_key;
let private_key = secret_or_private_key;
let keypair;
let method;
if (typeof secret_or_private_key !== "string") {
// use privateKey to generate keypairs, using algorithm
throw new Error("deriving keypair requires secret or private key");
}
else if (/^s/.test(secret_or_private_key)) {
// use secret to derive, secret has algorithm information already
const decoded = addressCodec.decodeSeed(secret);
algorithm =
decoded.type === "ed25519"
? "ed25519"
: guomi
? "sm2p256v1"
: "secp256k1";
method = select(algorithm);
keypair = method.deriveKeypair(decoded.bytes);
}
else {
// use private key to derive, could be raw privateKey or prefixed privateKey
if (secret_or_private_key.length === 64) {
// raw private key, has no information on algorithm
algorithm =
algorithm === "ed25519"
? "ed25519"
: guomi
? "sm2p256v1"
: "secp256k1";
}
else if (secret_or_private_key.length === 66) {
// prefixed private key, has information on algorithm
if (secret_or_private_key.slice(0, 2) === "00") {
algorithm = guomi ? "sm2p256v1" : "secp256k1";
}
else if (secret_or_private_key.slice(0, 2).toUpperCase() === "ED") {
algorithm = "ed25519";
}
else {
throw new Error("deriving keypair requires correct prefixed private key");
}
private_key = secret_or_private_key.slice(2);
}
else {
throw new Error("deriving keypair requires valid private key");
}
method = select(algorithm);
keypair = method.deriveKeypairWithPrivateKey(private_key);
}
const messageToVerify = hash("This test message should verify.");
const signature = method.sign(messageToVerify, keypair.privateKey);
if (method.verify(messageToVerify, signature, keypair.publicKey) !== true) {
throw new Error("derived keypair did not generate verifiable signature");
}
return keypair;
}
function deriveAddressFromBytes(publicKeyBytes) {
return addressCodec.encodeAccountID(Buffer.from(guomi
? (0, utils_1.computePublicKeyHashGm)(publicKeyBytes)
: (0, utils_1.computePublicKeyHash)(publicKeyBytes)));
}
function deriveAddress(publicKey) {
return deriveAddressFromBytes((0, common_1.funcHexToBytes)(publicKey));
}
function deriveNodeAddress(publicKey) {
const generatorBytes = addressCodec.decodeNodePublic(publicKey);
const accountPublicBytes = guomi
? (0, sm2p256v1_1.accountPublicFromPublicGenerator)(generatorBytes)
: (0, secp256k1_1.accountPublicFromPublicGenerator)(generatorBytes);
return deriveAddressFromBytes(accountPublicBytes);
}
function convertAddressToBytes(address) {
return addressCodec.decodeAddress(address).toJSON().data;
}
function convertBytesToAddress(bytes) {
return addressCodec.encodeAddress(bytes);
}
return {
// secp256k1,
// secp256k1guomi,
// ed25519,
// decodeSeed: addressCodec.decodeSeed
guomi,
token,
// for swtc libs
addressCodec,
deriveKeyPair: deriveKeypair,
hash,
seedFromPhrase: guomi ? utils_1.seedFromPhraseGm : utils_1.seedFromPhrase,
signTx,
verifyTx,
convertAddressToBytes,
convertBytesToAddress,
checkAddress: addressCodec.isValidAddress,
isValidAddress: addressCodec.isValidAddress,
// standards
deriveKeypair,
generateSeed,
sign,
verify,
deriveAddress,
deriveNodeAddress
};
}
//# sourceMappingURL=keypairs.js.map