@swtc/keypairs
Version:
swtc keypairs
334 lines • 15.3 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Factory = void 0;
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 = elliptic_1.eddsa("ed25519");
const Secp256k1 = 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 = 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 +
secp256k1_1.derivePrivateKey(entropy, options).toString(16, 64).toUpperCase();
const publicKey = 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 = common_1.funcBytesToHex(Secp256k1.keyFromPrivate(privateKey.slice(2))
.getPublic()
.encodeCompressed());
return { privateKey, publicKey };
},
sign: (message, privateKey) => {
return common_1.funcBytesToHex(Secp256k1.sign(hash(message), common_1.funcHexToBytes(privateKey), {
canonical: true
}).toDER());
},
verify: (message, signature, publicKey) => {
return Secp256k1.verify(hash(message), signature, common_1.funcHexToBytes(publicKey));
},
signTx: (message, privateKey) => {
return common_1.funcBytesToHex(Secp256k1.sign(message, common_1.funcHexToBytes(privateKey), {
canonical: true
}).toDER());
},
verifyTx: (message, signature, publicKey) => {
return Secp256k1.verify(message, signature, common_1.funcHexToBytes(publicKey));
}
};
const sm2p256v1 = {
deriveKeypair: (entropy, options = {}) => {
const prefix = "00";
const pri = sm2p256v1_1.derivePrivateKey(entropy, options);
const privateKey = prefix + pri.toString(16, 64).toUpperCase();
const publicKey = 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 = 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 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 = common_1.funcHexToBytes(message);
}
const keypair = sm_js_1.sm2.SM2KeyPair(null, new bn_js_1.default(privateKey, "hex"));
return 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 = 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 + common_1.funcBytesToHex(rawPrivateKey);
const publicKey = prefix + common_1.funcBytesToHex(Ed25519.keyFromSecret(rawPrivateKey).pubBytes());
return { privateKey, publicKey };
},
deriveKeypairWithPrivateKey: (rawPrivateKey) => {
const prefix = "ED";
const privateKey = prefix + rawPrivateKey.toUpperCase();
const publicKey = prefix +
common_1.funcBytesToHex(Ed25519.keyFromSecret(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
common_1.funcAssert(Array.isArray(message), "message must be array of octets");
return common_1.funcBytesToHex(Ed25519.sign(message, common_1.funcHexToBytes(privateKey).slice(1)).toBytes());
},
verify: (message, signature, publicKey) => {
return Ed25519.verify(message, common_1.funcHexToBytes(signature), 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, common_1.funcHexToBytes(privateKey).slice(1)).toHex();
},
verifyTx: (message, signature, publicKey) => {
return Ed25519.verify(message, common_1.funcHexToBytes(signature), common_1.funcHexToBytes(publicKey).slice(1));
}
};
const ed25519guomi = {
deriveKeypair: (entropy) => {
const prefix = "ED";
const rawPrivateKey = hash(entropy);
const privateKey = prefix + common_1.funcBytesToHex(rawPrivateKey);
const publicKey = prefix + common_1.funcBytesToHex(Ed25519.keyFromSecret(rawPrivateKey).pubBytes());
return { privateKey, publicKey };
},
deriveKeypairWithPrivateKey: (rawPrivateKey) => {
const prefix = "ED";
const privateKey = prefix + rawPrivateKey.toUpperCase();
const publicKey = prefix +
common_1.funcBytesToHex(Ed25519.keyFromSecret(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
common_1.funcAssert(Array.isArray(message), "message must be array of octets");
return common_1.funcBytesToHex(Ed25519.sign(message, common_1.funcHexToBytes(privateKey).slice(1)).toBytes());
},
verify: (message, signature, publicKey) => {
return Ed25519.verify(message, common_1.funcHexToBytes(signature), 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, common_1.funcHexToBytes(privateKey).slice(1)).toHex();
},
verifyTx: (message, signature, publicKey) => {
return Ed25519.verify(message, common_1.funcHexToBytes(signature), common_1.funcHexToBytes(publicKey).slice(1));
}
};
function generateSeed(options = {}) {
common_1.funcAssert(!options.entropy || options.entropy.length >= 16, "entropy too short");
const entropy = options.entropy ? options.entropy.slice(0, 16) : 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 = 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(common_1.funcHexToBytes(messageHex), privateKey);
}
function verify(messageHex, signature, publicKey) {
const algorithm = getAlgorithmFromKey(publicKey);
return select(algorithm).verify(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
? utils_1.computePublicKeyHashGm(publicKeyBytes)
: utils_1.computePublicKeyHash(publicKeyBytes)));
}
function deriveAddress(publicKey) {
return deriveAddressFromBytes(common_1.funcHexToBytes(publicKey));
}
function deriveNodeAddress(publicKey) {
const generatorBytes = addressCodec.decodeNodePublic(publicKey);
const accountPublicBytes = guomi
? sm2p256v1_1.accountPublicFromPublicGenerator(generatorBytes)
: 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
};
}
exports.Factory = Factory;
//# sourceMappingURL=keypairs.js.map