-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b42764d
commit 3f2ed43
Showing
11 changed files
with
7,419 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# BC-UR-Registry-BTC | ||
|
||
This repository is the BTC extension of [bc-ur-registry](https://github.com/KeystoneHQ/ur-registry) | ||
|
||
## Installing | ||
|
||
To install, run: | ||
|
||
```bash | ||
yarn add @keystonehq/bc-ur-registry-btc | ||
``` | ||
|
||
```bash | ||
npm install --save @keystonehq/bc-ur-registry-btc | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
// @ts-nocheck | ||
|
||
import { BtcSignRequest, CryptoKeypath, PathComponent, DataType } from "../src"; | ||
import * as uuid from "uuid"; | ||
|
||
describe("btc-sign-request", () => { | ||
it("should generate btc-sign-request", () => { | ||
const btcData = Buffer.from( | ||
"48656c6c6f2063727970746f20776f726c6421", | ||
"hex" | ||
); | ||
|
||
const signKeyPath = new CryptoKeypath( | ||
[ | ||
new PathComponent({ index: 44, hardened: true }), | ||
new PathComponent({ index: 0, hardened: true }), | ||
new PathComponent({ index: 0, hardened: true }), | ||
new PathComponent({ index: 0, hardened: false }), | ||
new PathComponent({ index: 0, hardened: false }), | ||
], | ||
Buffer.from("78230804", "hex") | ||
); | ||
|
||
const btcRequestId = "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"; | ||
const idBuffer = uuid.parse(btcRequestId) as Uint8Array; | ||
|
||
const btcSignRequest = new BtcSignRequest({ | ||
requestId: Buffer.from(idBuffer), | ||
signData: btcData, | ||
dataType: DataType.message, | ||
derivationPaths: [signKeyPath], | ||
addresses: ["1MjiyuupjWK5Ye13f8BAPvgby5WBuQXyJx"], | ||
origin: "btc wallet", | ||
}); | ||
|
||
const cborHex = btcSignRequest.toCBOR().toString("hex"); | ||
const ur = btcSignRequest.toUREncoder(1000).nextPart(); | ||
|
||
expect(ur).toBe( | ||
"ur:btc-sign-request/oladtpdagdndcawmgtfrkigrpmndutdnbtkgfssbjnaogufdihjzjzjlcxiajpkkjojyjlcxktjljpjzieclaxadaalytaaddyoeadlecsdwykaeykaeykaewkaewkaocykscnayaaahlykscpehgtiminkkkpkpjoimhggrechkiheheoiyetfwfpgdkoioidkkechgfwkpgyhdkkgeksamimidjyiacxkthsjzjzihjypffpsbdy" | ||
); | ||
const btcSignRequestDecoded = BtcSignRequest.fromCBOR( | ||
Buffer.from(cborHex, "hex") | ||
); | ||
expect(uuid.stringify(btcSignRequest.getRequestId())).toBe(btcRequestId); | ||
expect(btcSignRequest.getOrigin()).toBe("btc wallet"); | ||
expect(btcSignRequestDecoded.getSignData().toString("hex")).toEqual( | ||
"48656c6c6f2063727970746f20776f726c6421" | ||
); | ||
expect(btcSignRequestDecoded.getDerivationPaths()[0]).toEqual( | ||
"44'/0'/0'/0/0" | ||
); | ||
expect(btcSignRequestDecoded.getDataype()).toBe(DataType.message); | ||
|
||
expect(btcSignRequestDecoded.getAddress()[0]).toEqual( | ||
"1MjiyuupjWK5Ye13f8BAPvgby5WBuQXyJx" | ||
); | ||
}); | ||
|
||
it("should construct an btcSignRequest object from string", () => { | ||
const derivationHdPaths = ["m/44'/0'/0'/0/0"]; | ||
const xfps = ["78230804"]; | ||
const btcData = Buffer.from( | ||
"48656c6c6f2063727970746f20776f726c6421", | ||
"hex" | ||
); | ||
const requestID = "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"; | ||
const addresses = ["1MjiyuupjWK5Ye13f8BAPvgby5WBuQXyJx"]; | ||
|
||
const request = BtcSignRequest.constructBtcRequest( | ||
requestID, | ||
xfps, | ||
btcData, | ||
DataType.message, | ||
derivationHdPaths, | ||
addresses, | ||
"btc wallet" | ||
); | ||
const ur = request.toUREncoder(1000).nextPart(); | ||
expect(ur).toBe( | ||
"ur:btc-sign-request/oladtpdagdndcawmgtfrkigrpmndutdnbtkgfssbjnaogufdihjzjzjlcxiajpkkjojyjlcxktjljpjzieclaxadaalytaaddyoeadlecsdwykaeykaeykaewkaewkaocykscnayaaahlykscpehgtiminkkkpkpjoimhggrechkiheheoiyetfwfpgdkoioidkkechgfwkpgyhdkkgeksamimidjyiacxkthsjzjzihjypffpsbdy" | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// @ts-nocheck | ||
|
||
import { BtcSignature } from "../src"; | ||
import * as uuid from "uuid"; | ||
|
||
describe("btc-signature", () => { | ||
it("should generate btc-signature", () => { | ||
const signature = Buffer.from( | ||
"47e7b510784406dfa14d9fd13c3834128b49c56ddfc28edb02c5047219779adeed12017e2f9f116e83762e86f805c7311ea88fb403ff21900e069142b1fb310e", | ||
"hex" | ||
); | ||
const requestId = "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"; | ||
const idBuffer = uuid.parse(requestId) as Uint8Array; | ||
const pubKey = Buffer.from( | ||
"8e53e7b10656816de70824e3016fc1a277e77825e12825dc4f239f418ab2e04e", | ||
"hex" | ||
); | ||
|
||
const btcSignature = new BtcSignature( | ||
signature, | ||
Buffer.from(idBuffer), | ||
pubKey | ||
); | ||
|
||
const cborHex = btcSignature.toCBOR().toString("hex"); | ||
const ur = btcSignature.toUREncoder(1000).nextPart(); | ||
expect(ur).toBe( | ||
"ur:btc-signature/otadtpdagdndcawmgtfrkigrpmndutdnbtkgfssbjnaohdfzflvdrebeksfyamuroygtnettfneteebglugaskjnursamnuyaoskaajpcfktnyuewebgadkbdlnebyjtlskodmlnyaahstehckpdmyqzaxzmclmhbaammefwpazoehbaaxhdcxmnguvdpaamhflyjnvdaydkvladjlseoektvdksdavydedauogwcnnefpleprvtgloynbcfut" | ||
); | ||
const btcSignatureDecoded = BtcSignature.fromCBOR( | ||
Buffer.from(cborHex, "hex") | ||
); | ||
expect(uuid.stringify(btcSignatureDecoded.getRequestId())).toBe(requestId); | ||
expect(btcSignatureDecoded.getSignature().toString("hex")).toEqual( | ||
"47e7b510784406dfa14d9fd13c3834128b49c56ddfc28edb02c5047219779adeed12017e2f9f116e83762e86f805c7311ea88fb403ff21900e069142b1fb310e" | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
module.exports = { | ||
presets: [ | ||
["@babel/preset-env", { targets: { node: "current" } }], | ||
"@babel/preset-typescript", | ||
], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
{ | ||
"name": "@keystonehq/bc-ur-registry-btc", | ||
"version": "0.1.0", | ||
"description": "bc-ur-registry extension for BTC", | ||
"main": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"directories": { | ||
"lib": "src", | ||
"test": "__tests__" | ||
}, | ||
"files": [ | ||
"src", | ||
"dist" | ||
], | ||
"scripts": { | ||
"clean": "rm -rf ./dist", | ||
"start": "tsdx watch", | ||
"build": "tsdx build", | ||
"test": "jest --passWithNoTests" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"author": "Renfeng Shi<[email protected]>", | ||
"license": "ISC", | ||
"dependencies": { | ||
"@keystonehq/bc-ur-registry": "^0.5.4", | ||
"uuid": "^8.3.2" | ||
}, | ||
"devDependencies": { | ||
"@babel/preset-typescript": "^7.15.0", | ||
"@types/uuid": "^8.3.1", | ||
"tsdx": "^0.14.1", | ||
"typescript": "^4.6.2" | ||
}, | ||
"gitHead": "" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
import { | ||
CryptoKeypath, | ||
extend, | ||
DataItem, | ||
PathComponent, | ||
RegistryItem, | ||
DataItemMap, | ||
} from "@keystonehq/bc-ur-registry"; | ||
import { ExtendedRegistryTypes } from "./RegistryType"; | ||
import * as uuid from "uuid"; | ||
|
||
const { decodeToDataItem, RegistryTypes } = extend; | ||
|
||
export enum DataType { | ||
message = 1, | ||
} | ||
|
||
enum Keys { | ||
requestId = 1, | ||
signData, | ||
dataType, | ||
derivationPaths, | ||
addresses, | ||
origin, | ||
} | ||
|
||
type signRequestProps = { | ||
requestId: Buffer; | ||
signData: Buffer; | ||
dataType: DataType; | ||
derivationPaths: CryptoKeypath[]; | ||
addresses?: string[]; | ||
origin?: string; | ||
}; | ||
|
||
export class BtcSignRequest extends RegistryItem { | ||
private requestId: Buffer; | ||
private signData: Buffer; | ||
private dataType: DataType; | ||
private derivationPaths: CryptoKeypath[]; | ||
private addresses?: string[]; | ||
private origin?: string; | ||
|
||
getRegistryType = () => ExtendedRegistryTypes.BTC_SIGN_REQUEST; | ||
|
||
constructor(args: signRequestProps) { | ||
super(); | ||
this.requestId = args.requestId; | ||
this.signData = args.signData; | ||
this.dataType = args.dataType; | ||
this.derivationPaths = args.derivationPaths; | ||
this.addresses = args.addresses; | ||
this.origin = args.origin; | ||
} | ||
|
||
public getRequestId = () => this.requestId; | ||
public getSignData = () => this.signData; | ||
public getDataype = () => this.dataType; | ||
public getDerivationPaths = () => | ||
this.derivationPaths.map((key) => key.getPath()); | ||
public getAddress = () => this.addresses; | ||
public getOrigin = () => this.origin; | ||
|
||
public toDataItem = () => { | ||
const map: DataItemMap = {}; | ||
map[Keys.requestId] = new DataItem( | ||
this.requestId, | ||
RegistryTypes.UUID.getTag() | ||
); | ||
map[Keys.signData] = this.signData; | ||
map[Keys.dataType] = this.dataType; | ||
|
||
map[Keys.derivationPaths] = this.derivationPaths.map((item) => { | ||
const dataItem = item.toDataItem(); | ||
dataItem.setTag(item.getRegistryType().getTag()); | ||
return dataItem; | ||
}); | ||
|
||
if (this.addresses) { | ||
map[Keys.addresses] = this.addresses; | ||
} | ||
|
||
if (this.origin) { | ||
map[Keys.origin] = this.origin; | ||
} | ||
|
||
return new DataItem(map); | ||
}; | ||
|
||
public static fromDataItem = (dataItem: DataItem) => { | ||
const map = dataItem.getData(); | ||
|
||
const requestId = map[Keys.requestId] | ||
? map[Keys.requestId].getData() | ||
: undefined; | ||
|
||
const signData = map[Keys.signData]; | ||
|
||
const dataType = map[Keys.dataType]; | ||
|
||
const derivationPaths = map[Keys.derivationPaths].map((item: DataItem) => | ||
CryptoKeypath.fromDataItem(item) | ||
); | ||
|
||
const addresses = map[Keys.addresses] ? map[Keys.addresses] : undefined; | ||
|
||
const origin = map[Keys.origin] ? map[Keys.origin] : undefined; | ||
|
||
return new BtcSignRequest({ | ||
requestId, | ||
signData, | ||
dataType, | ||
derivationPaths, | ||
addresses, | ||
origin, | ||
}); | ||
}; | ||
|
||
public static fromCBOR = (_cborPayload: Buffer) => { | ||
const dataItem = decodeToDataItem(_cborPayload); | ||
return BtcSignRequest.fromDataItem(dataItem); | ||
}; | ||
|
||
public static constructBtcRequest( | ||
uuidString: string, | ||
xfps: string[], | ||
signData: Buffer, | ||
dataType: DataType, | ||
derivationHDPaths: string[], | ||
addresses?: string[], | ||
origin?: string | ||
) { | ||
const derivationHdPathObjects = derivationHDPaths.map((path, index) => { | ||
const paths = path.replace(/[m|M]\//, "").split("/"); | ||
const pathComponent = paths.map((path) => { | ||
const index = parseInt(path.replace("'", "")); | ||
let isHardened = false; | ||
if (path.endsWith("'")) { | ||
isHardened = true; | ||
} | ||
return new PathComponent({ index, hardened: isHardened }); | ||
}); | ||
return new CryptoKeypath(pathComponent, Buffer.from(xfps[index], "hex")); | ||
}); | ||
|
||
return new BtcSignRequest({ | ||
requestId: Buffer.from(uuid.parse(uuidString) as Uint8Array), | ||
signData, | ||
dataType: dataType || DataType.message, | ||
derivationPaths: derivationHdPathObjects, | ||
addresses: addresses || undefined, | ||
origin: origin || undefined, | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { | ||
extend, | ||
DataItem, | ||
RegistryItem, | ||
DataItemMap, | ||
} from "@keystonehq/bc-ur-registry"; | ||
import { ExtendedRegistryTypes } from "./RegistryType"; | ||
|
||
const { RegistryTypes, decodeToDataItem } = extend; | ||
|
||
enum Keys { | ||
requestId = 1, | ||
signature, | ||
publicKey, | ||
} | ||
|
||
export class BtcSignature extends RegistryItem { | ||
private requestId: Buffer; | ||
private signature: Buffer; | ||
private publicKey: Buffer; | ||
|
||
getRegistryType = () => ExtendedRegistryTypes.BTC_SIGNATURE; | ||
|
||
constructor(signature: Buffer, requestId: Buffer, publicKey: Buffer) { | ||
super(); | ||
this.signature = signature; | ||
this.requestId = requestId; | ||
this.publicKey = publicKey; | ||
} | ||
|
||
public getRequestId = () => this.requestId; | ||
public getSignature = () => this.signature; | ||
public getPublicKey = () => this.publicKey; | ||
public toDataItem = () => { | ||
const map: DataItemMap = {}; | ||
map[Keys.requestId] = new DataItem( | ||
this.requestId, | ||
RegistryTypes.UUID.getTag() | ||
); | ||
map[Keys.signature] = this.signature; | ||
map[Keys.publicKey] = this.publicKey; | ||
return new DataItem(map); | ||
}; | ||
|
||
public static fromDataItem = (dataItem: DataItem) => { | ||
const map = dataItem.getData(); | ||
const signature = map[Keys.signature]; | ||
const requestId = map[Keys.requestId].getData(); | ||
const authenticationPublicKey = map[Keys.publicKey]; | ||
return new BtcSignature(signature, requestId, authenticationPublicKey); | ||
}; | ||
|
||
public static fromCBOR = (_cborPayload: Buffer) => { | ||
const dataItem = decodeToDataItem(_cborPayload); | ||
return BtcSignature.fromDataItem(dataItem); | ||
}; | ||
} |
Oops, something went wrong.