Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 9 additions & 2 deletions packages/common-types/src/base/Point.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import BN from "bn.js";
import { ec as EllipticCurve } from "elliptic";

import { BNString, IPoint, KeyType, StringifiedType } from "../baseTypes/commonTypes";
import { BNString, IPoint, KeyType, StringifiedType, keyTypeToCurve } from "../baseTypes/commonTypes";

export class Point implements IPoint {
ecCurve: EllipticCurve;
Expand Down Expand Up @@ -34,12 +34,19 @@ export class Point implements IPoint {
}

static fromSEC1(value: string, keyType: KeyType): Point {
const ecCurve = new EllipticCurve(keyType.toString());
const ecCurve = keyTypeToCurve(keyType);
const key = ecCurve.keyFromPublic(value, "hex");
const pt = key.getPublic();
return new Point(pt.getX(), pt.getY(), keyType);
}

static fromPrivate(privateKey: BNString, keyType: KeyType): Point {
const ecCurve = keyTypeToCurve(keyType);
const key = ecCurve.keyFromPrivate(privateKey.toString("hex"), "hex");
const pt = key.getPublic();
return new Point(pt.getX(), pt.getY(), keyType);
}

toSEC1(compressed = false): string {
return this.ecCurve.keyFromPublic({ x: this.x.toString("hex"), y: this.y.toString("hex") }).getPublic(compressed, "hex");
}
Expand Down
15 changes: 14 additions & 1 deletion packages/common-types/src/baseTypes/commonTypes.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
import type { CustomAuthArgs } from "@toruslabs/customauth";
import BN from "bn.js";
import { curve } from "elliptic";
import { curve, ec as EllipticCurve } from "elliptic";

export enum KeyType {
"secp256k1",
"ed25519",
}
const curveED25519 = new EllipticCurve("ed25519");
const curveSECP256K1 = new EllipticCurve("secp256k1");

export function keyTypeToCurve(keyType: KeyType): EllipticCurve {
switch (keyType) {
case KeyType.ed25519:
return curveED25519;
case KeyType.secp256k1:
return curveSECP256K1;
default:
throw new Error("Invalid key type");
}
}

export type PubKeyType = "ecc";

Expand Down
1 change: 1 addition & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"@toruslabs/eccrypto": "^4.0.0",
"@toruslabs/http-helpers": "^5.0.0",
"@toruslabs/torus.js": "^12.0.1",
"@toruslabs/tweetnacl-js": "^1.0.4",
"bn.js": "^5.2.1",
"elliptic": "^6.5.4",
"json-stable-stringify": "^1.0.2"
Expand Down
70 changes: 62 additions & 8 deletions packages/core/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
EncryptedMessage,
FromJSONConstructor,
GenerateNewShareResult,
generatePrivate,
generatePrivateExcludingIndexes,
getPubKeyECC,
getPubKeyPoint,
Expand All @@ -20,6 +21,7 @@ import {
KEY_NOT_FOUND,
KeyDetails,
KeyType,
keyTypeToCurve,
LocalMetadataTransitions,
LocalTransitionData,
LocalTransitionShares,
Expand All @@ -42,9 +44,10 @@ import {
StringifiedType,
TKeyArgs,
TkeyStoreItemType,
toPrivKeyECC,
} from "@tkey/common-types";
import { generatePrivate } from "@toruslabs/eccrypto";
import { keccak256 } from "@toruslabs/torus.js";
// import nacl = require("@toruslabs/tweetnacl-js");
import * as nacl from "@toruslabs/tweetnacl-js";
import BN from "bn.js";
import { ec as EllipticCurve } from "elliptic";
import stringify from "json-stable-stringify";
Expand Down Expand Up @@ -111,7 +114,6 @@ class ThresholdKey implements ITKey {
this.serverTimeOffset = serverTimeOffset;

// temporary: TO FIX
// this.ecCurve = new EllipticCurve("secp256k1");
if (keyType) {
this.keyType = keyType;
this.ecCurve = new EllipticCurve(keyType.toString());
Expand Down Expand Up @@ -656,11 +658,26 @@ class ThresholdKey implements ITKey {
importedKey?: BN;
delete1OutOf1?: boolean;
} = {}): Promise<InitializeNewKeyResult> {
if (!importedKey) {
const tmpPriv = generatePrivate();
if (this.keyType === KeyType.secp256k1) {
const tmpPriv = importedKey ? importedKey : generatePrivate(this.ecCurve);
this._setKey(new BN(tmpPriv));
} else {
this._setKey(new BN(importedKey));
const seed = importedKey ? importedKey.toBuffer() : nacl.randomBytes(32);

const keyPair = nacl.sign.keyPair.fromSeed(seed);
// need to decode from le ??
const tempPriv = new BN(keyPair.secretKey);
this._setKey(tempPriv);

// encrypt and add to local metadata transitions
const encMsg = await this.encrypt(Buffer.from(seed));
await this.addLocalMetadataTransitions({ input: [{ message: JSON.stringify(encMsg), dateAdded: Date.now() }], privKey: [tempPriv] });

// testing and checking code - to remove
// const decMsg = await this.decrypt(encMsg);
// const decSeed = Buffer.from(decMsg).toString("hex");
// console.log("decSeed: ", decSeed);
// console.log("seed: ", seed);
}

// create a random poly and respective shares
Expand Down Expand Up @@ -1157,12 +1174,30 @@ class ThresholdKey implements ITKey {

async encrypt(data: Buffer): Promise<EncryptedMessage> {
if (!this.privKey) throw CoreError.privateKeyUnavailable();
return encrypt(getPubKeyECC(this.privKey), data);

let encKey: BN = this.privKey;
let curve = this.ecCurve;
if (this.keyType === KeyType.ed25519) {
// hash and umod to secp256k1
const secpCurve = keyTypeToCurve(KeyType.secp256k1);
encKey = new BN(keccak256(this.privKey.toBuffer())).umod(secpCurve.curve.n);
curve = secpCurve;
}
const keyPair = curve.keyFromPrivate(encKey.toBuffer());
const publicKey = keyPair.getPublic(false, "hex");
return encrypt(Buffer.from(publicKey, "hex"), data);
}

async decrypt(encryptedMessage: EncryptedMessage): Promise<Buffer> {
if (!this.privKey) throw CoreError.privateKeyUnavailable();
return decrypt(toPrivKeyECC(this.privKey), encryptedMessage);
// depend
let encKey: BN = this.privKey;
if (this.keyType === KeyType.ed25519) {
const secpCurve = keyTypeToCurve(KeyType.secp256k1);
// hash and umod to secp256k1
encKey = new BN(keccak256(this.privKey.toBuffer())).umod(secpCurve.curve.n);
}
return decrypt(encKey.toBuffer(), encryptedMessage);
}

async _setTKeyStoreItem(moduleName: string, data: TkeyStoreItemType): Promise<void> {
Expand Down Expand Up @@ -1263,6 +1298,25 @@ class ThresholdKey implements ITKey {
await this.inputShareStoreSafe(shareStore);
}

// Export Tkey
async exportFinalKey(): Promise<String> {
if (!this.metadata) {
throw CoreError.metadataUndefined();
}
if (!this.privKey) {
throw CoreError.privateKeyUnavailable();
}

if (this.keyType === KeyType.secp256k1) {
return this.privKey.toString("hex");
} else if (this.keyType === KeyType.ed25519) {
let result: EncryptedMessage = await this.storageLayer.getMetadata({privKey: this.privKey});
let seed = await this.decrypt(result);
return seed.toString("hex");
}
throw CoreError.default("Invalid KeyType");
}

toJSON(): StringifiedType {
return {
shares: this.shares,
Expand Down
5 changes: 3 additions & 2 deletions packages/core/src/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
ShareMap,
ShareStore,
StringifiedType,
toPrivKeyECC,
} from "@tkey/common-types";
import BN from "bn.js";
import stringify from "json-stable-stringify";
Expand Down Expand Up @@ -187,7 +186,9 @@ class Metadata implements IMetadata {
if (!encryptedShare) {
throw CoreError.encryptedShareStoreUnavailable(`${shareStore}`);
}
const rawDecrypted = await decrypt(toPrivKeyECC(shareStore.share.share), encryptedShare as EncryptedMessage);

// check for keyType
const rawDecrypted = await decrypt(shareStore.share.share.toBuffer(), encryptedShare as EncryptedMessage);
return ShareStore.fromJSON(JSON.parse(rawDecrypted.toString()));
}

Expand Down
39 changes: 22 additions & 17 deletions packages/storage-layer-torus/src/MockStorageLayer.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import {
generateID,
getPubKeyPoint,
IServiceProvider,
IStorageLayer,
KEY_NOT_FOUND,
KeyType,
MockStorageLayerArgs,
Point,
StringifiedType,
} from "@tkey/common-types";
import BN from "bn.js";
import stringify from "json-stable-stringify";

class MockStorageLayer implements IStorageLayer {
dataMap: {
[key: string]: unknown;
Expand Down Expand Up @@ -39,11 +39,11 @@ class MockStorageLayer implements IStorageLayer {
* Get metadata for a key
* @param privKey - If not provided, it will use service provider's share for decryption
*/
async getMetadata<T>(params: { serviceProvider?: IServiceProvider; privKey?: BN }): Promise<T> {
const { serviceProvider, privKey } = params;
async getMetadata<T>(params: { serviceProvider?: IServiceProvider; privKey?: BN; keyType: KeyType }): Promise<T> {
const { serviceProvider, privKey, keyType } = params;
let usedKey: BN;
if (!privKey) usedKey = serviceProvider.retrievePubKeyPoint().getX();
else usedKey = getPubKeyPoint(privKey).x;
else usedKey = Point.fromPrivate(privKey, keyType).x;

const fromMap = this.dataMap[usedKey.toString("hex")];
if (!fromMap) {
Expand All @@ -57,43 +57,48 @@ class MockStorageLayer implements IStorageLayer {
* @param input - data to post
* @param privKey - If not provided, it will use service provider's share for encryption
*/
async setMetadata<T>(params: { input: T; serviceProvider?: IServiceProvider; privKey?: BN }): Promise<{ message: string }> {
const { serviceProvider, privKey, input } = params;
async setMetadata<T>(params: { input: T; serviceProvider?: IServiceProvider; privKey?: BN; keyType: KeyType }): Promise<{ message: string }> {
const { serviceProvider, privKey, input, keyType } = params;
let usedKey: BN;
if (!privKey) usedKey = serviceProvider.retrievePubKeyPoint().getX();
else usedKey = getPubKeyPoint(privKey).x;
else usedKey = Point.fromPrivate(privKey, keyType).x;
this.dataMap[usedKey.toString("hex")] = stringify(input);
return { message: "success" };
}

async setMetadataStream<T>(params: { input: Array<T>; serviceProvider?: IServiceProvider; privKey?: Array<BN> }): Promise<{ message: string }> {
const { serviceProvider, privKey, input } = params;
async setMetadataStream<T>(params: {
input: Array<T>;
serviceProvider?: IServiceProvider;
privKey?: Array<BN>;
keyType: KeyType;
}): Promise<{ message: string }> {
const { serviceProvider, privKey, input, keyType } = params;
input.forEach((el, index) => {
let usedKey: BN;
if (!privKey || !privKey[index]) usedKey = serviceProvider.retrievePubKeyPoint().getX();
else usedKey = getPubKeyPoint(privKey[index]).x;
else usedKey = Point.fromPrivate(privKey[index], keyType).x;
this.dataMap[usedKey.toString("hex")] = stringify(el);
});

return { message: "success" };
}

async acquireWriteLock(params: { serviceProvider?: IServiceProvider; privKey?: BN }): Promise<{ status: number; id?: string }> {
const { serviceProvider, privKey } = params;
async acquireWriteLock(params: { serviceProvider?: IServiceProvider; privKey?: BN; keyType: KeyType }): Promise<{ status: number; id?: string }> {
const { serviceProvider, privKey, keyType } = params;
let usedKey: BN;
if (!privKey) usedKey = serviceProvider.retrievePubKeyPoint().getX();
else usedKey = getPubKeyPoint(privKey).x;
else usedKey = Point.fromPrivate(privKey, keyType).x;
if (this.lockMap[usedKey.toString("hex")]) return { status: 0 };
const id = generateID();
this.lockMap[usedKey.toString("hex")] = id;
return { status: 1, id };
}

async releaseWriteLock(params: { id: string; serviceProvider?: IServiceProvider; privKey?: BN }): Promise<{ status: number }> {
const { serviceProvider, privKey, id } = params;
async releaseWriteLock(params: { id: string; serviceProvider?: IServiceProvider; privKey?: BN; keyType: KeyType }): Promise<{ status: number }> {
const { serviceProvider, privKey, id, keyType } = params;
let usedKey: BN;
if (!privKey) usedKey = serviceProvider.retrievePubKeyPoint().getX();
else usedKey = getPubKeyPoint(privKey).x;
else usedKey = Point.fromPrivate(privKey, keyType).x;
if (!this.lockMap[usedKey.toString("hex")]) return { status: 0 };
if (id !== this.lockMap[usedKey.toString("hex")]) return { status: 2 };
this.lockMap[usedKey.toString("hex")] = null;
Expand Down
Loading