Skip to content

Commit

Permalink
feat: update hardwarecall
Browse files Browse the repository at this point in the history
  • Loading branch information
ZhenQian committed Aug 6, 2024
1 parent 7d64aa9 commit 0cd4169
Show file tree
Hide file tree
Showing 4 changed files with 3,025 additions and 2,842 deletions.
146 changes: 134 additions & 12 deletions __tests__/extended/QRHardwareCall.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { CryptoKeypath, PathComponent } from '../../src';
import { QRHardwareCall, QRHardwareCallType } from '../../src/extended/QRHardwareCall';
import {
QRHardwareCall,
QRHardwareCallType,
QRHardwareCallVersion,
} from '../../src/extended/QRHardwareCall';
import { KeyDerivation } from '../../src/extended/KeyDerivation';
import { Curve, DerivationAlgorithm, KeyDerivationSchema } from '../../src/extended/DerivationSchema';
import {
ChainType,
Curve,
DerivationAlgorithm,
KeyDerivationSchema,
} from '../../src/extended/DerivationSchema';

describe('QRHardwareCall', () => {
it('should generate QRHardwareCall', () => {
Expand All @@ -22,7 +31,10 @@ describe('QRHardwareCall', () => {
const schema2 = new KeyDerivationSchema(keyPath2, Curve.ed25519);

const keyDerivation = new KeyDerivation([schema1, schema2]);
const qrHardwareCall = new QRHardwareCall(QRHardwareCallType.KeyDerivation, keyDerivation);
const qrHardwareCall = new QRHardwareCall(
QRHardwareCallType.KeyDerivation,
keyDerivation,
);

const hex = qrHardwareCall.toCBOR().toString('hex');
expect(hex).toBe(
Expand All @@ -35,23 +47,133 @@ describe('QRHardwareCall', () => {
);
});

it('Test QRHardwareCall Version1 Example', () => {
const keyPath1 = new CryptoKeypath([
new PathComponent({ index: 44, hardened: true }),
new PathComponent({ index: 501, hardened: true }),
new PathComponent({ index: 1, hardened: true }),
]);

const schema1 = new KeyDerivationSchema(
keyPath1,
Curve.ed25519,
DerivationAlgorithm.slip10,
ChainType.SOL,
);
const keyPath2 = new CryptoKeypath([
new PathComponent({ index: 44, hardened: true }),
new PathComponent({ index: 501, hardened: true }),
new PathComponent({ index: 0, hardened: true }),
new PathComponent({ index: 0, hardened: true }),
new PathComponent({ index: 0, hardened: false }),
]);
const schema2 = new KeyDerivationSchema(
keyPath2,
Curve.ed25519,
DerivationAlgorithm.slip10,
ChainType.SOL,
);

const keyPath3 = new CryptoKeypath([
new PathComponent({ index: 44, hardened: true }),
new PathComponent({ index: 501, hardened: true }),
new PathComponent({ index: 0, hardened: true }),
]);
const schema3 = new KeyDerivationSchema(
keyPath3,
Curve.ed25519,
DerivationAlgorithm.slip10,
ChainType.SOL,
);

const keyDerivation = new KeyDerivation([schema1, schema2, schema3]);
const qrHardwareCall = new QRHardwareCall(
QRHardwareCallType.KeyDerivation,
keyDerivation,
'XXX Wallet',
QRHardwareCallVersion.V1,
);

const hex = qrHardwareCall.toCBOR().toString('hex');
expect(hex).toBe(
'a4010002d90515a10183d90516a401d90130a10186182cf51901f5f501f5020103000463534f4cd90516a401d90130a1018a182cf51901f5f500f500f500f4020103000463534f4cd90516a401d90130a10186182cf51901f5f500f5020103000463534f4c036a5858582057616c6c65740401',
);

const ur = qrHardwareCall.toUREncoder(1000).nextPart();
expect(ur).toBe(
'ur:qr-hardware-call/oxadaeaotaahbzoyadlstaahcmoxadtaaddyoyadlncsdwykcfadykykadykaoadaxaeaaiagugwgstaahcmoxadtaaddyoyadlecsdwykcfadykykaeykaeykaewkaoadaxaeaaiagugwgstaahcmoxadtaaddyoyadlncsdwykcfadykykaeykaoadaxaeaaiagugwgsaximhdhdhdcxhghsjzjzihjyaaadfgdprppm',
);
});

it('Test Generate QRHardwareCall Version1 Example2', () => {
const keyPath1 = new CryptoKeypath([
new PathComponent({ index: 44, hardened: true }),
new PathComponent({ index: 0, hardened: true }),
new PathComponent({ index: 0, hardened: true }),
]);

const schema1 = new KeyDerivationSchema(
keyPath1,
Curve.secp256k1,
DerivationAlgorithm.slip10,
ChainType.BTC,
);
const keyPath2 = new CryptoKeypath([
new PathComponent({ index: 44, hardened: true }),
new PathComponent({ index: 501, hardened: true }),
new PathComponent({ index: 0, hardened: true }),
new PathComponent({ index: 0, hardened: true }),
new PathComponent({ index: 0, hardened: false }),
]);
const schema2 = new KeyDerivationSchema(
keyPath2,
Curve.ed25519,
DerivationAlgorithm.slip10,
ChainType.SOL,
);

const keyPath3 = new CryptoKeypath([
new PathComponent({ index: 44, hardened: true }),
new PathComponent({ index: 501, hardened: true }),
new PathComponent({ index: 1, hardened: true }),
]);
const schema3 = new KeyDerivationSchema(
keyPath3,
Curve.ed25519,
DerivationAlgorithm.slip10,
ChainType.SOL,
);

const keyDerivation = new KeyDerivation([schema1, schema2, schema3]);
const qrHardwareCall = new QRHardwareCall(
QRHardwareCallType.KeyDerivation,
keyDerivation,
'XXX Wallet',
QRHardwareCallVersion.V1,
);

const hex = qrHardwareCall.toCBOR().toString('hex');
expect(hex).toBe(
'a4010002d90515a10183d90516a301d90130a10186182cf500f500f502000300d90516a401d90130a1018a182cf51901f5f500f500f500f4020103000463534f4cd90516a401d90130a10186182cf51901f5f501f5020103000463534f4c036a5858582057616c6c65740401',
);

const ur = qrHardwareCall.toUREncoder(1000).nextPart();
expect(ur).toBe(
'ur:qr-hardware-call/oxadaeaotaahbzoyadlstaahcmotadtaaddyoyadlncsdwykaeykaeykaoaeaxaetaahcmoxadtaaddyoyadlecsdwykcfadykykaeykaeykaewkaoadaxaeaaiagugwgstaahcmoxadtaaddyoyadlncsdwykcfadykykadykaoadaxaeaaiagugwgsaximhdhdhdcxhghsjzjzihjyaaaduojkiede',
);
});

it('should decode QRHardwareCall', () => {
const hex =
'a2010002d90515a10182d90516a301d90130a10186182cf500f500f502000300d90516a301d90130a1018a182cf51901f5f500f500f500f402010300';
const qrHardwareCall = QRHardwareCall.fromCBOR(
Buffer.from(hex, 'hex'),
);
const qrHardwareCall = QRHardwareCall.fromCBOR(Buffer.from(hex, 'hex'));
expect(qrHardwareCall.getType()).toBe(QRHardwareCallType.KeyDerivation);

const keyDerivation = qrHardwareCall.getParams() as KeyDerivation;
const schemas = keyDerivation.getSchemas();
expect(schemas[0].getCurve()).toBe(Curve.secp256k1);
expect(schemas[0].getAlgo()).toBe(DerivationAlgorithm.slip10);
expect(schemas[0].getKeypath().getPath()).toBe(
'44\'/0\'/0\'',
);
expect(schemas[1].getKeypath().getPath()).toBe(
'44\'/501\'/0\'/0\'/0',
);
expect(schemas[0].getKeypath().getPath()).toBe("44'/0'/0'");
expect(schemas[1].getKeypath().getPath()).toBe("44'/501'/0'/0'/0");
});
});
158 changes: 155 additions & 3 deletions src/extended/DerivationSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,180 @@ enum Keys {
keyPath = 1,
curve,
algo,
chainType,
}

export enum Curve {
secp256k1,
ed25519
ed25519,
}

export enum DerivationAlgorithm {
slip10,
bip32ed25519
bip32ed25519,
}

export enum ChainType {
BTC,
ETH,
SOL,
XRP,
ADA,
TRX,
LTC,
BCH,
APT,
SUI,
DASH,
AR,
XLM,
TIA,
ATOM,
DYM,
OSMO,
INJ,
CRO,
KAVA,
LUNC,
AXL,
LUNA,
AKT,
STRD,
SCRT,
BLD,
CTK,
EVMOS,
STARS,
XPRT,
SOMM,
JUNO,
IRIS,
DVPN,
ROWAN,
REGEN,
BOOT,
GRAV,
IXO,
NGM,
IOV,
UMEE,
QCK,
TGD,
}

export const chainTypeToString = (chainType: ChainType): string => {
switch (chainType) {
case ChainType.BTC:
return 'BTC';
case ChainType.ETH:
return 'ETH';
case ChainType.SOL:
return 'SOL';
case ChainType.XRP:
return 'XRP';
case ChainType.ADA:
return 'ADA';
case ChainType.TRX:
return 'TRX';
case ChainType.LTC:
return 'LTC';
case ChainType.BCH:
return 'BCH';
case ChainType.APT:
return 'APT';
case ChainType.SUI:
return 'SUI';
case ChainType.DASH:
return 'DASH';
case ChainType.AR:
return 'AR';
case ChainType.XLM:
return 'XLM';
case ChainType.TIA:
return 'TIA';
case ChainType.ATOM:
return 'ATOM';
case ChainType.DYM:
return 'DYM';
case ChainType.OSMO:
return 'OSMO';
case ChainType.INJ:
return 'INJ';
case ChainType.CRO:
return 'CRO';
case ChainType.KAVA:
return 'KAVA';
case ChainType.LUNC:
return 'LUNC';
case ChainType.AXL:
return 'AXL';
case ChainType.LUNA:
return 'LUNA';
case ChainType.AKT:
return 'AKT';
case ChainType.STRD:
return 'STRD';
case ChainType.SCRT:
return 'SCRT';
case ChainType.BLD:
return 'BLD';
case ChainType.CTK:
return 'CTK';
case ChainType.EVMOS:
return 'EVMOS';
case ChainType.STARS:
return 'STARS';
case ChainType.XPRT:
return 'XPRT';
case ChainType.SOMM:
return 'SOMM';
case ChainType.JUNO:
return 'JUNO';
case ChainType.IRIS:
return 'IRIS';
case ChainType.DVPN:
return 'DVPN';
case ChainType.ROWAN:
return 'ROWAN';
case ChainType.REGEN:
return 'REGEN';
case ChainType.BOOT:
return 'BOOT';
case ChainType.GRAV:
return 'GRAV';
case ChainType.IXO:
return 'IXO';
case ChainType.NGM:
return 'NGM';
case ChainType.IOV:
return 'IOV';
case ChainType.UMEE:
return 'UMEE';
case ChainType.QCK:
return 'QCK';
case ChainType.TGD:
return 'TGD';
default:
throw new Error(`Unknown ChainType: ${chainType}`);
}
};

export class KeyDerivationSchema extends RegistryItem {
getRegistryType = () => RegistryTypes.KEY_DERIVATION_SCHEMA;

constructor(
private keypath: CryptoKeypath,
private curve: Curve = Curve.secp256k1,
private algo: DerivationAlgorithm = DerivationAlgorithm.slip10,
private chainType?: ChainType,
) {
super();
}

public getKeypath = (): CryptoKeypath => this.keypath;
public getCurve = (): Curve => this.curve;
public getAlgo = (): DerivationAlgorithm => this.algo;
public getChainType = (): ChainType => this.chainType;

public toDataItem = (): DataItem => {
const map: DataItemMap = {};
Expand All @@ -42,6 +190,9 @@ export class KeyDerivationSchema extends RegistryItem {
map[Keys.keyPath] = dataItem;
map[Keys.curve] = this.curve;
map[Keys.algo] = this.algo;
if (this.chainType) {
map[Keys.chainType] = chainTypeToString(this.chainType);
}
return new DataItem(map);
};

Expand All @@ -50,7 +201,8 @@ export class KeyDerivationSchema extends RegistryItem {
const keypaths = CryptoKeypath.fromDataItem(map[Keys.keyPath]);
const curve = map[Keys.curve];
const algo = map[Keys.algo];
return new KeyDerivationSchema(keypaths, curve, algo);
const chainType = map[Keys.chainType];
return new KeyDerivationSchema(keypaths, curve, algo, chainType);
};

public static fromCBOR = (_cborPayload: Buffer): KeyDerivationSchema => {
Expand Down
Loading

0 comments on commit 0cd4169

Please sign in to comment.