Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: feat split key #110

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
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
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,13 @@
"crypto": "^1.0.1",
"crypto-js": "^4.1.1",
"dotenv": "^16.0.0",
"eciesjs": "^0.3.16",
"ethers": "^5.7.2",
"filereader": "^0.10.3",
"form-data": "^4.0.0",
"jimp": "^0.16.1",
"nft.storage": "^7.0.0",
"secrets.js-grempe": "^2.0.0",
"uuid": "^8.3.2",
"web3": "^1.8.0"
}
Expand Down
80 changes: 63 additions & 17 deletions src/vwbl/api/VWBLApi.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import axios from "axios";
import { encrypt, decrypt, PrivateKey, PublicKey } from 'eciesjs';
import * as secrets from "secrets.js-grempe";

export class VWBLApi {
private instance;
Expand All @@ -11,29 +13,73 @@ export class VWBLApi {
key: string,
signature: string,
address?: string,
hasNonce?: boolean,
autoMigration?: boolean
autoMigration: boolean = true
) {
await this.instance.post("/keys", {
document_id: documentId,
chain_id: chainId,
key,
signature,
address,
has_nonce: hasNonce,
auto_migration: autoMigration,
});
const keyAndSigMapping = await this.constructKeyAndSigMapping(key, signature);
await this.instance.post("/api/v1/keys", {
userAddress: address,
documentId,
chainId,
autoMigration,
keyAndSigMapping
})
}

async migrateKey(
documentId: string,
chainId: number,
key: string,
signature: string,
address?: string,
autoMigration: boolean = true
) {
const keyAndSigMapping = await this.constructKeyAndSigMapping(key, signature);
await this.instance.post("api/v1/migrate", {
userAddress: address,
documentId,
chainId,
autoMigration,
keyAndSigMapping
})
}

async getKey(documentId: string, chainId: number, signature: string, address?: string): Promise<string> {
const response = await this.instance.get(
`/keys/${documentId}/${chainId}?signature=${signature}&address=${address}`
);
return response.data.documentKey.key;
const privKey = new PrivateKey();
const userPubKey = "0x" + privKey.publicKey.toHex();
const sigMapping = await this.contructSigMapping(signature);
const encryptedKeys = (await this.instance.get(
`/api/v1/keys/${documentId}/${chainId}?userPubkey=${userPubKey}&userAddress=${address}&userSig=${sigMapping}`
)).data.encryptedKeys;
const keys = encryptedKeys.map((k: string) => decrypt(privKey.toHex(), Buffer.from(k, 'hex')).toString());
return secrets.hex2str(secrets.combine(keys))
}

async getSignMessage(contractAddress: string, chainId: number, address?: string): Promise<string> {
const response = await this.instance.get(`/signature/${contractAddress}/${chainId}?address=${address}`);
const response = await this.instance.get(`/sign_message/${contractAddress}/${chainId}?address=${address}`);
return response.data.signMessage;
}
}

private async constructKeyAndSigMapping(key: string, signature: string) {
const validatorInfo = (await this.instance.get("/api/v1/validator_info").catch(() => undefined))?.data;
const shares = secrets.share(secrets.str2hex(key), validatorInfo.m, validatorInfo.n)
const keyAndSigMapping: { [key: string]: string } = {};
for (let i = 0; i < validatorInfo.m; i++) {
const shareAndSig = shares[i] + " " + signature
const pubKey = new PublicKey(Buffer.from(validatorInfo.publicKeys[i], 'hex'));
const encryptedShareAndSig = encrypt(pubKey.toHex(), Buffer.from(shareAndSig)).toString('hex');
keyAndSigMapping[validatorInfo.publicKeys[i]] = encryptedShareAndSig;
}
return keyAndSigMapping;
}

private async contructSigMapping(signature: string) {
const validatorInfo = (await this.instance.get("/api/v1/validator_info").catch(() => undefined))?.data;
const sigMapping: { [key: string]: string } = {};
for (let i = 0; i < validatorInfo.m; i++) {
const pubKey = new PublicKey(Buffer.from(validatorInfo.publicKeys[i], 'hex'));
const encryptedSig = encrypt(pubKey.toHex(), Buffer.from(signature));
sigMapping[validatorInfo.publicKeys[i]] = encryptedSig.toString('hex');
}
return JSON.stringify(sigMapping);
}
}
5 changes: 2 additions & 3 deletions src/vwbl/erc721/VWBL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,19 +279,18 @@ export class VWBL extends VWBLBase {
*
* @param tokenId - The ID of NFT
* @param key - The key generated by {@link VWBL.createKey}
* @param hasNonce
* @param autoMigration
*
*/
setKey = async (tokenId: number, key: string, hasNonce?: boolean, autoMigration?: boolean): Promise<void> => {
setKey = async (tokenId: number, key: string, autoMigration?: boolean): Promise<void> => {
const { documentId } = await this.nft.getTokenInfo(tokenId);
const chainId =
"web3" in this.opts ? await this.opts.web3.eth.getChainId() : await this.opts.ethersSigner.getChainId();
const signerAddress =
"web3" in this.opts
? await this._getAddressBySigner(this.opts.web3)
: await this._getAddressBySigner(this.opts.ethersSigner);
return await this._setKey(documentId, chainId, key, signerAddress, hasNonce, autoMigration);
return await this._setKey(documentId, chainId, key, signerAddress, autoMigration);
};

/**
Expand Down
Loading