-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[lightspark-sdk] add remote signing support in lightspark client (#6089)
- adds enum for signing key types - adds property to `NodeKeyCache` to save signing key type - changes `Requester` to add signing data specific to signing key type - adds wasm packed `lightspark_crypto` lib - related PR: lightsparkdev/lightspark-crypto-uniffi#31 - adds `loadNodeSigningKey` function to client which handles both rsa and secp key types for OSK and remote signing - updates documentation to reflect new `loadNodeSigningKey` function - adds `SigningKeyLoader` classes to handle loading logic Tested using lightspark-cli lightsparkdev/webdev#6203 GitOrigin-RevId: 07daa2cd7c01610a65f5a809d37c6e69130d5330
- Loading branch information
1 parent
425d1f9
commit 2dd5ba9
Showing
23 changed files
with
1,753 additions
and
90 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
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
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,50 @@ | ||
import { createHash } from "crypto"; | ||
import secp256k1 from "secp256k1"; | ||
import { hexToBytes, SigningKeyType, type CryptoInterface } from "../index.js"; | ||
|
||
interface Alias { | ||
alias: string; | ||
} | ||
|
||
function isAlias(key: CryptoKey | Alias): key is Alias { | ||
return "alias" in key; | ||
} | ||
|
||
export abstract class SigningKey { | ||
readonly type: SigningKeyType; | ||
|
||
constructor(type: SigningKeyType) { | ||
this.type = type; | ||
} | ||
|
||
abstract sign(data: Uint8Array): Promise<ArrayBuffer>; | ||
} | ||
|
||
export class RSASigningKey extends SigningKey { | ||
constructor( | ||
private readonly privateKey: CryptoKey | Alias, | ||
private readonly cryptoImpl: CryptoInterface, | ||
) { | ||
super(SigningKeyType.RSASigningKey); | ||
} | ||
|
||
async sign(data: Uint8Array) { | ||
const key = isAlias(this.privateKey) | ||
? this.privateKey.alias | ||
: this.privateKey; | ||
return this.cryptoImpl.sign(key, data); | ||
} | ||
} | ||
|
||
export class Secp256k1SigningKey extends SigningKey { | ||
constructor(private readonly privateKey: string) { | ||
super(SigningKeyType.Secp256k1SigningKey); | ||
} | ||
|
||
async sign(data: Uint8Array) { | ||
const keyBytes = new Uint8Array(hexToBytes(this.privateKey)); | ||
const hash = createHash("sha256").update(data).digest(); | ||
const signResult = secp256k1.ecdsaSign(hash, keyBytes); | ||
return signResult.signature; | ||
} | ||
} |
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
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,4 @@ | ||
export enum SigningKeyType { | ||
RSASigningKey = "RSASigningKey", | ||
Secp256k1SigningKey = "Secp256k1SigningKey", | ||
} |
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
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 @@ | ||
export const bytesToHex = (bytes: Uint8Array): string => { | ||
return bytes.reduce((acc: string, byte: number) => { | ||
return (acc += ("0" + byte.toString(16)).slice(-2)); | ||
}, ""); | ||
}; | ||
|
||
export const hexToBytes = (hex: string): Uint8Array => { | ||
const bytes: number[] = []; | ||
|
||
for (let c = 0; c < hex.length; c += 2) { | ||
bytes.push(parseInt(hex.substr(c, 2), 16)); | ||
} | ||
|
||
return Uint8Array.from(bytes); | ||
}; |
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
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 |
---|---|---|
@@ -1,5 +1,5 @@ | ||
{ | ||
"extends": "@lightsparkdev/tsconfig/base.json", | ||
"include": ["src"], | ||
"include": ["src", "src/crypto/types.ts"], | ||
"exclude": ["test", "node_modules", "dist"] | ||
} |
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
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
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
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
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,87 @@ | ||
import { | ||
LightsparkSigningException, | ||
type CryptoInterface, | ||
type NodeKeyCache, | ||
type Requester, | ||
type SigningKey, | ||
} from "@lightsparkdev/core"; | ||
import { | ||
isMasterSeedSigningKeyLoaderArgs, | ||
isNodeIdAndPasswordSigningKeyLoaderArgs, | ||
MasterSeedSigningKeyLoader, | ||
NodeIdAndPasswordSigningKeyLoader, | ||
type SigningKeyLoader, | ||
type SigningKeyLoaderArgs, | ||
} from "./SigningKeyLoader.js"; | ||
|
||
/** | ||
* A cache for SigningKeyLoaders associated with nodes. | ||
*/ | ||
export default class NodeKeyLoaderCache { | ||
private idToLoader: Map<string, SigningKeyLoader>; | ||
|
||
constructor( | ||
private readonly nodeKeyCache: NodeKeyCache, | ||
private readonly cryptoImpl: CryptoInterface = DefaultCrypto, | ||
) { | ||
this.idToLoader = new Map(); | ||
} | ||
|
||
/** | ||
* Sets the signing key loader for a node. | ||
* Instantiates a signing key loader based on the type of args passed in by the user. | ||
* | ||
* @param nodeId The ID of the node to get the key for | ||
* @param loaderArgs Loader arguments for loading the key | ||
* @param requester Requester used for loading the key | ||
*/ | ||
setLoader( | ||
nodeId: string, | ||
loaderArgs: SigningKeyLoaderArgs, | ||
requester: Requester, | ||
) { | ||
let loader: SigningKeyLoader; | ||
if (isNodeIdAndPasswordSigningKeyLoaderArgs(loaderArgs)) { | ||
loader = new NodeIdAndPasswordSigningKeyLoader( | ||
{ nodeId, ...loaderArgs }, | ||
requester, | ||
this.cryptoImpl, | ||
); | ||
} else if (isMasterSeedSigningKeyLoaderArgs(loaderArgs)) { | ||
loader = new MasterSeedSigningKeyLoader({ ...loaderArgs }); | ||
} else { | ||
throw new LightsparkSigningException("Invalid signing key loader args"); | ||
} | ||
|
||
this.idToLoader.set(nodeId, loader); | ||
} | ||
|
||
/** | ||
* Gets the key for a node using the loader set by [setLoader] | ||
* | ||
* @param id The ID of the node to get the key for | ||
* @returns The loaded key | ||
*/ | ||
async getKeyWithLoader(id: string): Promise<SigningKey | undefined> { | ||
if (this.nodeKeyCache.hasKey(id)) { | ||
return this.nodeKeyCache.getKey(id); | ||
} | ||
|
||
const loader = this.idToLoader.get(id); | ||
if (!loader) { | ||
throw new LightsparkSigningException( | ||
"No signing key loader found for node " + id, | ||
); | ||
} | ||
const loaderResult = await loader.loadSigningKey(); | ||
if (!loaderResult) { | ||
return; | ||
} | ||
|
||
return this.nodeKeyCache.loadKey( | ||
id, | ||
{ key: loaderResult.key }, | ||
loaderResult.type, | ||
); | ||
} | ||
} |
Oops, something went wrong.