Skip to content
This repository was archived by the owner on Mar 20, 2024. It is now read-only.
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@a-block/a-blockjs",
"version": "2.0.0",
"version": "2.0.1",
"description": "API wrapper to access the ABlock network",
"main": "lib/index.js",
"types": "lib/index.d.ts",
Expand Down
1 change: 1 addition & 0 deletions src/interfaces/error.interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export enum IErrorInternal {
UnableToFindNonEmptyAddresses = 'Unable to find addresses that contain assets',
InvalidNetworkResponse = 'Invalid network response',
UnableToSignMessage = 'Unable to sign message',
UnableToVerifyMessage = 'Unable to verify message',
NoHostsProvided = 'No hosts provided',
NoKeypairsProvided = 'No key-pairs provided',
NoPassPhraseProvided = 'No passphrase provided',
Expand Down
3 changes: 2 additions & 1 deletion src/interfaces/success.interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ export enum ISuccessNotary {

export enum ISuccessInternal {
ClientInitialized = 'Client initialized',
MessageSigned = 'Message successfully signed',
MessageSigned = 'Successfully signed message',
MessageVirified = 'Successfully verified message',
RbPaymentProcessing = 'Receipt-based payment processing',
PendingRbPaymentsFetched = 'Succesfully fetched pending receipt-based transactions',
AddressesReconstructed = 'Addresses have successfully been reconstructed',
Expand Down
39 changes: 30 additions & 9 deletions src/services/ablock.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,9 @@ export class ABlockWallet {
/**
* Initialize an instance of the client with a provided master key
*
* @param {IClientConfig} config - Additional configuration parameters
* @param {IMasterKeyEncrypted} masterKey - Master key
* @param {IClientConfig} config - Additional configuration parameters
* @param initOffline - Optionally initialize the client without initializing network settings
*
* @return {*} {IClientResponse}
* @memberof ABlockWallet
*/
Expand Down Expand Up @@ -144,11 +143,10 @@ export class ABlockWallet {
/**
* Initialize an instance of the wallet with a provided seed phrase
*
* @param {IClientConfig} config - Additional configuration parameters
* @param {string} seedPhrase - Seed phrase
* @param {IClientConfig} config - Additional configuration parameters
* @param initOffline - Optionally initialize the client without initializing network settings
* @return {*} {IClientResponse}
* @param initOffline - Optionally initialize the client without initializing network settings
*
* @memberof ABlockWallet
*/
public async fromSeed(
Expand All @@ -157,7 +155,7 @@ export class ABlockWallet {
initOffline = false,
): Promise<IClientResponse> {
this.keyMgmt = new mgmtClient();
const initIResult = this.keyMgmt.fromSeed(config.passphrase, seedPhrase);
const initIResult = this.keyMgmt.fromSeed(seedPhrase, config.passphrase);
if (!initOffline) {
const initNetworkIResult = await this.initNetwork(config);
if (initNetworkIResult.status === 'error') {
Expand All @@ -184,7 +182,7 @@ export class ABlockWallet {
* Common network initialization (retrieval of PoW list for compute and storage)
*
* @param {IClientConfig} config - Configuration parameters
*
* @return {*} {IClientResponse}
* @memberof ABlockWallet
*/
public async initNetwork(config: IClientConfig): Promise<IClientResponse> {
Expand Down Expand Up @@ -239,6 +237,7 @@ export class ABlockWallet {
*
* @private
* @param {IClientConfig} config - Additional configuration parameters
* @return {*} {IClientResponse}
* @memberof ABlockWallet
*/
private async initNetworkForHost(
Expand Down Expand Up @@ -601,10 +600,10 @@ export class ABlockWallet {
* @return {*} {Promise<IClientResponse>}
* @memberof ABlockWallet
*/
async signMessage(
signMessage(
keyPairsToSignWith: IKeypairEncrypted[],
message: string,
): Promise<IClientResponse> {
): IClientResponse {
try {
if (this.keyMgmt === undefined) throw new Error(IErrorInternal.ClientNotInitialized);
const keyPairs = throwIfErr(this.keyMgmt.decryptKeypairs(keyPairsToSignWith));
Expand All @@ -624,6 +623,28 @@ export class ABlockWallet {
}
}

verifyMessage(
message: string,
signatures: IGenericKeyPair<string>,
keyPairs: IKeypairEncrypted[],
): IClientResponse {
try {
if (this.keyMgmt === undefined) throw new Error(IErrorInternal.ClientNotInitialized);
const keyPairsUnencrypted = throwIfErr(this.keyMgmt.decryptKeypairs(keyPairs));
throwIfErr(this.keyMgmt.verifyMessage(message, signatures, keyPairsUnencrypted));
return {
status: 'success',
reason: ISuccessInternal.MessageVirified,
} as IClientResponse;
} catch (error) {
return {
status: 'error',
reason: `${error}`,
} as IClientResponse;
}
}


/**
* Make a payment of a specified token amount to a payment address
*
Expand Down
35 changes: 23 additions & 12 deletions src/services/mgmt.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
TEMP_ADDRESS_VERSION,
} from '../mgmt';
import { concatTypedArrays, getBytesString, getStringBytes, truncateByBytesUTF8 } from '../utils';
import { getBytesHexString } from '../utils/general.utils';
import { getBytesHexString, getHexStringBytes } from '../utils/general.utils';

export class mgmtClient {
private passphraseKey: Uint8Array;
Expand Down Expand Up @@ -80,8 +80,8 @@ export class mgmtClient {
/**
* Init the client with a provided master key
*
* @param {string} passphraseKey
* @param {IMasterKeyEncrypted} masterKey
* @param {string} passphraseKey
* @return {*} {IResult<void>}
* @memberof mgmtClient
*/
Expand All @@ -99,8 +99,8 @@ export class mgmtClient {
/**
* Init the client with a provided seed phrase
*
* @param {string} passphraseKey
* @param {string} seedPhrase
* @param {string} passphraseKey
* @return {*} {IResult<IMasterKeyEncrypted>}
* @memberof mgmtClient
*/
Expand Down Expand Up @@ -481,16 +481,27 @@ export class mgmtClient {
* @memberof mgmtClient
*/
public signMessage(keypairs: IKeypair[], message: string): IResult<IGenericKeyPair<string>> {
try {
const signatures: IGenericKeyPair<string> = {};
for (const keypair of keypairs) {
const signature = nacl.sign.detached(Buffer.from(message), keypair.secretKey);
signatures[getBytesHexString(keypair.publicKey)] = getBytesHexString(signature);
}
return ok(signatures);
} catch {
return err(IErrorInternal.UnableToSignMessage);
if (keypairs.length < 1)
return err(IErrorInternal.InvalidInputs);
const signatures: IGenericKeyPair<string> = {};
for (const keypair of keypairs) {
const signature = nacl.sign.detached(Buffer.from(message), keypair.secretKey);
signatures[getBytesHexString(keypair.publicKey)] = getBytesHexString(signature);
}
if (Object.keys(signatures).length < 1) return err(IErrorInternal.UnableToSignMessage);
return ok(signatures);
}

public verifyMessage(message: string, signatures: IGenericKeyPair<string>, keypairs: IKeypair[]): IResult<boolean> {
console.log(keypairs.length, Object.keys(signatures).length)
if (keypairs.length < 1 || Object.keys(signatures).length != keypairs.length)
return err(IErrorInternal.InvalidInputs);
for (const keypair of keypairs) {
const sig = signatures[getBytesHexString(keypair.publicKey)]
if (!sig || !nacl.sign.detached.verify(Buffer.from(message), getHexStringBytes(sig), keypair.publicKey))
return err(IErrorInternal.UnableToVerifyMessage);
}
return ok(true);
}

/**
Expand Down
60 changes: 58 additions & 2 deletions src/tests/__tests__/ablock.service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ test('init wallet without optional config fields', async () => {

test('init wallet locally and then connect', async () => {
await ablockInstance.initNew({ passphrase: '' }, true).then((res) => {
console.log(res)
expect(res.status).toBe('success');
});

Expand All @@ -44,7 +43,6 @@ test('init wallet locally and then connect', async () => {
};

await ablockInstance.initNetwork(config).then((res) => {
console.log(res)
expect(res.status).toBe('success');
});
});
Expand Down Expand Up @@ -79,3 +77,61 @@ test('handles key-pair re-generation from wallet seed phrase', async () => {
),
).toEqual(utxoAddressList);
});

test('sign message with given keypairs', async () => {
const config = {
mempoolHost: 'http://49.12.234.10:3003',
passphrase: '',
};
const MSG = 'hello, world';

await ablockInstance.initNew(config).then((res) => {
expect(res.status).toBe('success');
});

const kp = ablockInstance.getNewKeypair([]).content?.newKeypairResponse;
const kpAddr = kp?.address;

expect(kp).toBeDefined();
expect(kpAddr).toBeDefined();

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const kp1 = ablockInstance.getNewKeypair([kpAddr!]).content?.newKeypairResponse;

expect(kp1).toBeDefined();

const keypairs = [kp!, kp1!];

expect(keypairs).toBeDefined();

const signatures = ablockInstance.signMessage(keypairs, MSG).content?.signMessageResponse;

expect(signatures).toBeDefined();

const result = ablockInstance.verifyMessage(MSG, signatures!, keypairs)

expect(result.status).toBe('success');

const kp2 = ablockInstance.getNewKeypair([kpAddr!, kp1!.address]).content?.newKeypairResponse;

expect(kp2).toBeDefined();

const keypairs1 = [kp!, kp2!];

const result1 = ablockInstance.verifyMessage(MSG, signatures!, keypairs1)
console.log('RESULT 1: ', result1)
expect(result1.status).toBe('error');

// if (kp.content?.newKeypairResponse && kp1?.content?.newKeypairResponse)
// keypairs = [kp.content.newKeypairResponse, kp1.content.newKeypairResponse];

// if (keypairs) {
// const signatures = await ablockInstance.signMessage(keypairs, MSG);
// ¨ const result = await ablockInstance.verifyMessage(MSG, signatures.content?.signMessageResponse, keypairs);
// console.log(result)
// }

// const kp = ablockInstance.getNewKeypair([]);

// await ablockInstance.signMessage(,)
});