From 5252dffacfaeacf17c95defbc2e35d91c5bf97b8 Mon Sep 17 00:00:00 2001 From: himanshu Date: Thu, 4 Apr 2024 13:25:06 +0530 Subject: [PATCH] return final ed25519 key in seed hex format --- src/helpers/keyUtils.ts | 12 ++++++------ src/helpers/nodeUtils.ts | 19 +++---------------- src/torus.ts | 13 ++++++------- test/sapphire_devnet_ed25519.test.ts | 18 +++++++++++------- 4 files changed, 26 insertions(+), 36 deletions(-) diff --git a/src/helpers/keyUtils.ts b/src/helpers/keyUtils.ts index 6f40635..a08c04f 100644 --- a/src/helpers/keyUtils.ts +++ b/src/helpers/keyUtils.ts @@ -56,14 +56,13 @@ function adjustScalarBytes(bytes: Buffer): Buffer { } /** Convenience method that creates public key and other stuff. RFC8032 5.1.5 */ -export function getEd25519ExtendedPublicKey(keyHex: BN): { +export function getEd25519ExtendedPublicKey(keyBuffer: Buffer): { scalar: BN; point: curve.base.BasePoint; } { const len = 32; const G = ed25519Curve.g; const N = ed25519Curve.n; - const keyBuffer = keyHex.toArrayLike(Buffer); if (keyBuffer.length !== 32) { log.error("Invalid seed for ed25519 key derivation", keyBuffer.length); @@ -104,10 +103,10 @@ export function encodeEd25519Point(point: curve.base.BasePoint) { return enc; } -export const generateEd25519KeyData = async (ed25519Seed: BN): Promise => { +export const generateEd25519KeyData = async (ed25519Seed: Buffer): Promise => { const finalEd25519Key = getEd25519ExtendedPublicKey(ed25519Seed); const encryptionKey = getSecpKeyFromEd25519(finalEd25519Key.scalar); - const encryptedSeed = await encrypt(Buffer.from(encryptionKey.point.encodeCompressed("hex"), "hex"), ed25519Seed.toArrayLike(Buffer)); + const encryptedSeed = await encrypt(Buffer.from(encryptionKey.point.encodeCompressed("hex"), "hex"), ed25519Seed); const encData: EncryptedSeed = { enc_text: encryptedSeed.ciphertext.toString("hex"), metadata: encParamsBufToHex(encryptedSeed), @@ -132,7 +131,8 @@ export const generateEd25519KeyData = async (ed25519Seed: BN): Promise => { +export const generateSecp256k1KeyData = async (scalarBuffer: Buffer): Promise => { + const scalar = new BN(scalarBuffer); const randomNonce = new BN(generatePrivateKey(secp256k1Curve, Buffer)); const oAuthKey = scalar.sub(randomNonce).umod(secp256k1Curve.curve.n); const oAuthKeyPair = secp256k1Curve.keyFromPrivate(oAuthKey.toString("hex").padStart(64, "0")); @@ -202,7 +202,7 @@ export const generateShares = async ( serverTimeOffset: number, nodeIndexes: number[], nodePubkeys: INodePub[], - privKey: BN + privKey: Buffer ) => { const keyData = keyType === "ed25519" ? await generateEd25519KeyData(privKey) : await generateSecp256k1KeyData(privKey); const { metadataNonce, oAuthKeyScalar: oAuthKey, encryptedSeed, metadataSigningKey } = keyData; diff --git a/src/helpers/nodeUtils.ts b/src/helpers/nodeUtils.ts index cd2340c..97ebec9 100644 --- a/src/helpers/nodeUtils.ts +++ b/src/helpers/nodeUtils.ts @@ -2,7 +2,6 @@ import { INodePub, LEGACY_NETWORKS_ROUTE_MAP, TORUS_LEGACY_NETWORK_TYPE, TORUS_N import { generatePrivate, getPublic } from "@toruslabs/eccrypto"; import { generateJsonRPCObject, get, post } from "@toruslabs/http-helpers"; import BN from "bn.js"; -import base58 from "bs58"; import { curve, ec } from "elliptic"; import { getRandomBytes } from "ethereum-cryptography/random"; @@ -38,15 +37,7 @@ import { normalizeLegacyKeysResult, thresholdSame, } from "./common"; -import { - derivePubKey, - encodeEd25519Point, - generateAddressFromPrivKey, - generateAddressFromPubKey, - generatePrivateKey, - generateShares, - keccak256, -} from "./keyUtils"; +import { derivePubKey, generateAddressFromPrivKey, generateAddressFromPubKey, generatePrivateKey, generateShares, keccak256 } from "./keyUtils"; import { lagrangeInterpolation } from "./langrangeInterpolatePoly"; import { decryptNodeData, decryptSeedData, getMetadata, getOrSetNonce } from "./metadataUtils"; @@ -217,8 +208,7 @@ export async function retrieveOrImportShare(params: { finalImportedShares = newImportedShares; } else if (!useDkg) { const bufferKey = keyType === "secp256k1" ? generatePrivateKey(ecCurve, Buffer) : await getRandomBytes(32); - const importedKey = new BN(bufferKey); - const generatedShares = await generateShares(ecCurve, keyType, serverTimeOffset, indexes, nodePubkeys, importedKey); + const generatedShares = await generateShares(ecCurve, keyType, serverTimeOffset, indexes, nodePubkeys, Buffer.from(bufferKey)); finalImportedShares = [...finalImportedShares, ...generatedShares]; } @@ -745,15 +735,12 @@ export async function retrieveOrImportShare(params: { if (keyType === "secp256k1") { finalPrivKey = keyWithNonce; } else if (keyType === "ed25519") { - const finalPubKeyPair = ecCurve.keyFromPublic({ x: finalPubKey.getX().toString("hex"), y: finalPubKey.getY().toString("hex") }); - const encodedPubKey = encodeEd25519Point(finalPubKeyPair.getPublic()); if (keyWithNonce && !nonceResult.seed) { throw new Error("Invalid data, seed data is missing for ed25519 key, Please report this bug"); } else if (keyWithNonce && nonceResult.seed) { // console.log("nonceResult.seed", nonceResult.seed, keyWithNonce); const decryptedSeed = await decryptSeedData(nonceResult.seed, new BN(keyWithNonce, "hex")); - const totalLength = decryptedSeed.length + encodedPubKey.length; - finalPrivKey = base58.encode(Buffer.concat([decryptedSeed, encodedPubKey], totalLength)); + finalPrivKey = decryptedSeed.toString("hex"); } } else { throw new Error(`Invalid keyType: ${keyType}`); diff --git a/src/torus.ts b/src/torus.ts index 25c5608..d9c2e44 100644 --- a/src/torus.ts +++ b/src/torus.ts @@ -11,7 +11,6 @@ import { import { decrypt, generatePrivate, getPublic } from "@toruslabs/eccrypto"; import { generateJsonRPCObject, get, post, setAPIKey, setEmbedHost } from "@toruslabs/http-helpers"; import BN from "bn.js"; -import base58 from "bs58"; import { curve, ec as EC } from "elliptic"; import { config } from "./config"; @@ -22,6 +21,7 @@ import { generateAddressFromPrivKey, generateAddressFromPubKey, generateShares, + getEd25519ExtendedPublicKey, getMetadata, getNonce, getOrSetNonce, @@ -234,17 +234,16 @@ class Torus { } } if (this.keyType === "ed25519") { - privKeyBuffer = Buffer.from(base58.decode(newPrivateKey)); - if (privKeyBuffer.length !== 64) { + privKeyBuffer = Buffer.from(newPrivateKey, "hex"); + if (privKeyBuffer.length !== 32) { throw new Error("Invalid private key length for given ed25519 key"); } } - const finalPrivKey = this.keyType === "secp256k1" ? privKeyBuffer : privKeyBuffer.subarray(0, 32); - const privKeyBn = new BN(finalPrivKey, 16); - const sharesData = await generateShares(this.ec, this.keyType, this.serverTimeOffset, nodeIndexes, nodePubkeys, privKeyBn); + const sharesData = await generateShares(this.ec, this.keyType, this.serverTimeOffset, nodeIndexes, nodePubkeys, privKeyBuffer); if (this.keyType === "ed25519") { - const ed25519PubKey = privKeyBuffer.subarray(32); + const ed25519Key = getEd25519ExtendedPublicKey(privKeyBuffer); + const ed25519PubKey = encodeEd25519Point(ed25519Key.point); const encodedPubKey = encodeEd25519Point(sharesData[0].final_user_point); const importedPubKey = Buffer.from(ed25519PubKey).toString("hex"); const derivedPubKey = encodedPubKey.toString("hex"); diff --git a/test/sapphire_devnet_ed25519.test.ts b/test/sapphire_devnet_ed25519.test.ts index ab451c5..8c1af13 100644 --- a/test/sapphire_devnet_ed25519.test.ts +++ b/test/sapphire_devnet_ed25519.test.ts @@ -1,6 +1,7 @@ import { TORUS_SAPPHIRE_NETWORK } from "@toruslabs/constants"; import NodeManager from "@toruslabs/fetch-node-details"; import BN from "bn.js"; +import base58 from "bs58"; import { expect } from "chai"; import faker from "faker"; @@ -69,9 +70,12 @@ describe("torus utils ed25519 sapphire devnet", function () { const token = generateIdToken(email, "ES256"); // const privKeyBuffer = new BN(generatePrivateKey(ec, Buffer)); // key exported from phantom wallet - const privHex = "BjremmcjdFWexYJWcNSsT3U8ekuq6KnenBCSvxVfx2fQuvWbZQzDtQuAuXtQzcgxNY9CRyVNXJu2W5Rgt7ufQDh"; + const privB58 = "BjremmcjdFWexYJWcNSsT3U8ekuq6KnenBCSvxVfx2fQuvWbZQzDtQuAuXtQzcgxNY9CRyVNXJu2W5Rgt7ufQDh"; const nodeDetails = await TORUS_NODE_MANAGER.getNodeDetails({ verifier: TORUS_TEST_VERIFIER, verifierId: email }); const torusNodeEndpoints = nodeDetails.torusNodeSSSEndpoints; + + const decodedKey = Buffer.from(base58.decode(privB58)); + const seedKey = decodedKey.subarray(0, 32).toString("hex"); const result = await torus.importPrivateKey( torusNodeEndpoints, nodeDetails.torusIndexes, @@ -79,10 +83,10 @@ describe("torus utils ed25519 sapphire devnet", function () { TORUS_TEST_VERIFIER, { verifier_id: email }, token, - privHex + seedKey ); expect(result.finalKeyData.walletAddress).eql("3TTBP4g4UZNH1Tga1D4D6tBGrXUpVXcWt1PX2W19CRqM"); - expect(result.finalKeyData.privKey).to.be.equal(privHex); + expect(result.finalKeyData.privKey).to.be.equal(seedKey); const token1 = generateIdToken(email, "ES256"); const result1 = await torus.retrieveShares( @@ -94,7 +98,7 @@ describe("torus utils ed25519 sapphire devnet", function () { nodeDetails.torusNodePub ); expect(result1.finalKeyData.walletAddress).eql("3TTBP4g4UZNH1Tga1D4D6tBGrXUpVXcWt1PX2W19CRqM"); - expect(result.finalKeyData.privKey).to.be.equal(privHex); + expect(result.finalKeyData.privKey).to.be.equal(seedKey); const result2 = await torus.getPublicAddress(torusNodeEndpoints, nodeDetails.torusNodePub, { verifier: TORUS_TEST_VERIFIER, @@ -130,7 +134,7 @@ describe("torus utils ed25519 sapphire devnet", function () { walletAddress: "7iBcf5du7C7pCocbvoXHDbNXnzF9hSTNRuRiqfGC56Th", X: "738dfd57d80945defc6d3bc4deeeffbcecf344a4186b1e756eae54c5f60a4b63", Y: "7082c093c550e1069935a6f7f639901c84e14e4030a8561cba4b8ccfd7efb263", - privKey: "AV2s1hzK6xWHNPeSaaKiiJtgbDSjTx9LjDN9AtPhf3t7mAzxCjf9mDx25UzPrEHS8HcswFzSx4eSxCEEPmmyyEX", + privKey: "082d9495b9147bac19699ae3109606cbaeea1bf65772b6d7e652ebf77f67f783", }, metadata: { pubNonce: { @@ -205,7 +209,7 @@ describe("torus utils ed25519 sapphire devnet", function () { token, nodeDetails.torusNodePub ); - expect(result.finalKeyData.privKey).to.be.equal("5gcMa5vaPupHmFbDLeQR14odwCke5W3pF9y92BuLjFSACKuyNNCAEYfh3yZ7KyVJpZsjjpwZpneshfzB5ae6P89c"); + expect(result.finalKeyData.privKey).to.be.equal("ea39cc89d2d8b8403858d1c518fe82e2500cc83e472ba86d006323b57835a519"); }); it("should fetch pub address of tss verifier id", async function () { @@ -328,7 +332,7 @@ describe("torus utils ed25519 sapphire devnet", function () { walletAddress: "HK9Xo2UgjuMNxBi6WxX76hfQm9oTtJdDUSGKFhzGQiSo", X: "6002549f42c1f3504652ce4b3fb1cbff4f1eaa1b66551313dd9c44d48b31a63d", Y: "44af643f9200d11c5f60212de9470f92806df18eeea730a8736e4570611761f2", - privKey: "2SDsHqpEGTszmk73SyFu1tR85bK2kt7HmnBercBSiBZpHpYHBiqpquG8ARhRuDWXGquTM7NVRva3xFMSJ8sd2aQ3", + privKey: "47c471c6c3b53f751e39feae967359b9258a790a30f2db394625f76b0c84ada0", }, oAuthKeyData: { walletAddress: "DybMLmBwiPqt8GXpDW2MwHi5ZqEtrbgxgwcf7shPdTWg",