Skip to content

Commit

Permalink
return final ed25519 key in seed hex format
Browse files Browse the repository at this point in the history
  • Loading branch information
himanshu committed Apr 4, 2024
1 parent 0acead9 commit 5252dff
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 36 deletions.
12 changes: 6 additions & 6 deletions src/helpers/keyUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -104,10 +103,10 @@ export function encodeEd25519Point(point: curve.base.BasePoint) {
return enc;
}

export const generateEd25519KeyData = async (ed25519Seed: BN): Promise<PrivateKeyData> => {
export const generateEd25519KeyData = async (ed25519Seed: Buffer): Promise<PrivateKeyData> => {
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),
Expand All @@ -132,7 +131,8 @@ export const generateEd25519KeyData = async (ed25519Seed: BN): Promise<PrivateKe
};
};

export const generateSecp256k1KeyData = async (scalar: BN): Promise<PrivateKeyData> => {
export const generateSecp256k1KeyData = async (scalarBuffer: Buffer): Promise<PrivateKeyData> => {
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"));
Expand Down Expand Up @@ -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;
Expand Down
19 changes: 3 additions & 16 deletions src/helpers/nodeUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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";

Expand Down Expand Up @@ -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];
}

Expand Down Expand Up @@ -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}`);
Expand Down
13 changes: 6 additions & 7 deletions src/torus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -22,6 +21,7 @@ import {
generateAddressFromPrivKey,
generateAddressFromPubKey,
generateShares,
getEd25519ExtendedPublicKey,
getMetadata,
getNonce,
getOrSetNonce,
Expand Down Expand Up @@ -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");
Expand Down
18 changes: 11 additions & 7 deletions test/sapphire_devnet_ed25519.test.ts
Original file line number Diff line number Diff line change
@@ -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";

Expand Down Expand Up @@ -69,20 +70,23 @@ 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,
nodeDetails.torusNodePub,
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(
Expand All @@ -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,
Expand Down Expand Up @@ -130,7 +134,7 @@ describe("torus utils ed25519 sapphire devnet", function () {
walletAddress: "7iBcf5du7C7pCocbvoXHDbNXnzF9hSTNRuRiqfGC56Th",
X: "738dfd57d80945defc6d3bc4deeeffbcecf344a4186b1e756eae54c5f60a4b63",
Y: "7082c093c550e1069935a6f7f639901c84e14e4030a8561cba4b8ccfd7efb263",
privKey: "AV2s1hzK6xWHNPeSaaKiiJtgbDSjTx9LjDN9AtPhf3t7mAzxCjf9mDx25UzPrEHS8HcswFzSx4eSxCEEPmmyyEX",
privKey: "082d9495b9147bac19699ae3109606cbaeea1bf65772b6d7e652ebf77f67f783",
},
metadata: {
pubNonce: {
Expand Down Expand Up @@ -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 () {
Expand Down Expand Up @@ -328,7 +332,7 @@ describe("torus utils ed25519 sapphire devnet", function () {
walletAddress: "HK9Xo2UgjuMNxBi6WxX76hfQm9oTtJdDUSGKFhzGQiSo",
X: "6002549f42c1f3504652ce4b3fb1cbff4f1eaa1b66551313dd9c44d48b31a63d",
Y: "44af643f9200d11c5f60212de9470f92806df18eeea730a8736e4570611761f2",
privKey: "2SDsHqpEGTszmk73SyFu1tR85bK2kt7HmnBercBSiBZpHpYHBiqpquG8ARhRuDWXGquTM7NVRva3xFMSJ8sd2aQ3",
privKey: "47c471c6c3b53f751e39feae967359b9258a790a30f2db394625f76b0c84ada0",
},
oAuthKeyData: {
walletAddress: "DybMLmBwiPqt8GXpDW2MwHi5ZqEtrbgxgwcf7shPdTWg",
Expand Down

0 comments on commit 5252dff

Please sign in to comment.