Skip to content

Commit

Permalink
Merge pull request #240 from labscommunity/saam/ec
Browse files Browse the repository at this point in the history
Saam/ec
  • Loading branch information
rosmcmahon authored Jan 20, 2025
2 parents 29901f4 + a2e1a5c commit fe1b446
Show file tree
Hide file tree
Showing 24 changed files with 883 additions and 155 deletions.
7 changes: 5 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{
"ponicode.testSettings.testLocation.locationType": "Same folder as source file",
"ponicode.testSettings.testLocation.path": "{rootDir}/{filePath}/{fileName}.test.{ext}"
}
"ponicode.testSettings.testLocation.path": "{rootDir}/{filePath}/{fileName}.test.{ext}",
"files.insertFinalNewline": true,
"files.trimTrailingWhitespace": true,
"files.trimFinalNewlines": true
}
40 changes: 33 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"clean:bundle": "rimraf bundles",
"clean": "npm run clean:dist && npm run clean:package && npm run clean:bundle",
"prepublishOnly": "npm run clean && npm run build",
"test": "mocha test/*.ts && echo \"NOW RUN => 'npm run test:web' <= \" ",
"test": "mocha --file src/node/shims.ts test/*.ts && echo \"NOW RUN => 'npm run test:web' <= \" ",
"test:web": "npm run bundle:web && webpack --config-name web-tests && opener test/web/web.html",
"prettier:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\"",
"prettier:write": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
Expand Down Expand Up @@ -100,6 +100,7 @@
"node": ">=18"
},
"dependencies": {
"@arweave/wasm-secp256k1": "^0.0.6",
"arconnect": "^0.4.2",
"asn1.js": "^5.4.1",
"base64-js": "^1.5.1",
Expand Down
20 changes: 16 additions & 4 deletions src/common/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import * as ArweaveUtils from "./lib/utils";
import Silo from "./silo";
import Chunks from "./chunks";
import Blocks from "./blocks";
import { KeyType, PrivateKey, PublicKey, fromJWK } from "./lib/crypto/keys";

export interface Config {
api: ApiConfig;
Expand Down Expand Up @@ -83,7 +84,7 @@ export default class Arweave {

public async createTransaction(
attributes: Partial<CreateTransactionInterface>,
jwk?: JWKInterface | "use_wallet"
keyData?: JWKInterface | "use_wallet" | PrivateKey | PublicKey
): Promise<Transaction> {
const transaction: Partial<CreateTransactionInterface> = {};

Expand All @@ -95,9 +96,20 @@ export default class Arweave {
);
}

if (attributes.owner == undefined) {
if (jwk && jwk !== "use_wallet") {
transaction.owner = jwk.n;
if (attributes.owner == undefined && keyData && keyData !== "use_wallet") {
let pk: PublicKey;
if (keyData instanceof PrivateKey){
pk = await keyData.public()
} else if (keyData instanceof PublicKey) {
pk = keyData;
} else {
pk = await fromJWK(keyData as JsonWebKey)
.then(sk => sk.public());
}
transaction.owner = await pk.identifier()
.then(id => ArweaveUtils.bufferTob64Url(id));
if (pk.type === KeyType.EC_SECP256K1) {
transaction.owner = "";
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/common/lib/crypto/crypto-interface.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { JWKInterface } from "../wallet";
import { PrivateKey } from "./keys";

export interface SignatureOptions {
saltLength?: number;
Expand All @@ -8,7 +9,7 @@ export default interface CryptoInterface {
generateJWK(): Promise<JWKInterface>;

sign(
jwk: JWKInterface,
jwk: JWKInterface | PrivateKey,
data: Uint8Array,
options?: SignatureOptions
): Promise<Uint8Array>;
Expand Down
4 changes: 4 additions & 0 deletions src/common/lib/crypto/keys/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { RSAPrivateKey, RSAPublicKey } from "./rsa";
export { SECP256k1PrivateKey, SECP256k1PublicKey } from "./secp256k1";
export { KeyType, PrivateKey, PublicKey } from "./interface";
export { fromJWK, fromIdentifier } from "./utils";
93 changes: 93 additions & 0 deletions src/common/lib/crypto/keys/interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
export enum KeyType {
RSA_65537 = "rsa_65537",
EC_SECP256K1 = "ec_secp256k1",
};

export type Format = "jwk" | "raw";

export interface SerializationParams<T extends Format = Format> {
format: T;
}

export interface SigningParams {
payload: Uint8Array;
isDigest?: boolean;
}

export interface VerifyingParams {
payload: Uint8Array;
signature: Uint8Array;
isDigest?: boolean;
}

export interface EncryptionParams {
secret: Uint8Array;

}

export interface DecryptionParams {
payload: Uint8Array;
}

export abstract class PrivateKey {
public readonly type: KeyType;

constructor({type}: {type: KeyType}) {
this.type = type;
}
static async new(_: any): Promise<PrivateKey> {
throw new Error(`PrivateKey does not implement instantiation interface.`);
}
static async deserialize(_: any): Promise<PrivateKey> {
throw new Error(`PrivateKey does not implement deserialization interface.`);
}
abstract serialize(params: SerializationParams): Promise<JsonWebKey | Uint8Array>;
abstract sign(params: SigningParams): Promise<Uint8Array>;
abstract public(): Promise<PublicKey>;
public async decrypt(_: DecryptionParams): Promise<Uint8Array> {
throw new Error(`PrivateKey ${this.type} does not provide decription interface.`);
}
}

export abstract class PublicKey {
public readonly type: KeyType;
constructor({type}: {type: KeyType}) {
this.type = type;
}
static async deserialize(_: any): Promise<PublicKey> {
throw new Error(`PublicKey does not implement deserialization interface.`);
}
abstract serialize(params: SerializationParams): Promise<JsonWebKey | Uint8Array>;
abstract verify(params: VerifyingParams): Promise<boolean>;
abstract identifier(): Promise<Uint8Array>;
public async encrypt(_: EncryptionParams): Promise<Uint8Array> {
throw new Error(`PrivateKey ${this.type} does not provide encyrption interface.`);
}
}

export const getInitializationOptions = (type: KeyType): AlgorithmIdentifier | RsaHashedKeyGenParams | EcKeyGenParams => {
switch(type) {
case KeyType.RSA_65537:
return {
name: "RSA-PSS",
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: {
name: "SHA-256"
}
};
default:
throw new Error(`Unsupported RSA KeyType ${type}`);
}
}

export const getSigningParameters = (type: KeyType): AlgorithmIdentifier | RsaPssParams | EcdsaParams => {
switch(type) {
case KeyType.RSA_65537:
return {
name: "RSA-PSS",
saltLength: 32,
};
default:
throw new Error(`Unsupported RSA KeyType ${type}`);
}
}
Loading

0 comments on commit fe1b446

Please sign in to comment.