mirror of https://github.com/waku-org/js-waku.git
Reduce buffer usage (#521)
This commit is contained in:
parent
2dc8764be2
commit
cfc5eee4ff
|
@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- docs: Various improvements.
|
- docs: Various improvements.
|
||||||
- Ran `npm audit fix`.
|
- Ran `npm audit fix`.
|
||||||
- `Waku.dial` accepts protocols expected from the peer. Defaults to Waku Relay only.
|
- `Waku.dial` accepts protocols expected from the peer. Defaults to Waku Relay only.
|
||||||
|
- Deprecated `hexToBuf` & `bufToHex` in favour of `hexToBytes` & `bytesToHex` to move towards removing the `buffer` polyfill.
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import "@ethersproject/shims";
|
import "@ethersproject/shims";
|
||||||
|
|
||||||
import { PublicKeyMessage } from "./messaging/wire";
|
import { PublicKeyMessage } from "./messaging/wire";
|
||||||
import { hexToBuf, equalByteArrays, bufToHex } from "js-waku/lib/utils";
|
import { hexToBytes, equalByteArrays, bytesToHex } from "js-waku/lib/utils";
|
||||||
import * as sigUtil from "eth-sig-util";
|
import * as sigUtil from "eth-sig-util";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,8 +28,8 @@ export async function createPublicKeyMessage(
|
||||||
|
|
||||||
return new PublicKeyMessage({
|
return new PublicKeyMessage({
|
||||||
encryptionPublicKey: encryptionPublicKey,
|
encryptionPublicKey: encryptionPublicKey,
|
||||||
ethAddress: hexToBuf(address),
|
ethAddress: hexToBytes(address),
|
||||||
signature: hexToBuf(signature),
|
signature: hexToBytes(signature),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ function buildMsgParams(encryptionPublicKey: Uint8Array, fromAddress: string) {
|
||||||
version: "1",
|
version: "1",
|
||||||
},
|
},
|
||||||
message: {
|
message: {
|
||||||
encryptionPublicKey: bufToHex(encryptionPublicKey),
|
encryptionPublicKey: bytesToHex(encryptionPublicKey),
|
||||||
ownerAddress: fromAddress,
|
ownerAddress: fromAddress,
|
||||||
},
|
},
|
||||||
// Refers to the keys of the *types* object below.
|
// Refers to the keys of the *types* object below.
|
||||||
|
@ -79,7 +79,7 @@ export async function signEncryptionKey(
|
||||||
|
|
||||||
console.log("TYPED SIGNED:" + JSON.stringify(result));
|
console.log("TYPED SIGNED:" + JSON.stringify(result));
|
||||||
|
|
||||||
return hexToBuf(result);
|
return hexToBytes(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,13 +88,13 @@ export async function signEncryptionKey(
|
||||||
export function validatePublicKeyMessage(msg: PublicKeyMessage): boolean {
|
export function validatePublicKeyMessage(msg: PublicKeyMessage): boolean {
|
||||||
const recovered = sigUtil.recoverTypedSignature_v4({
|
const recovered = sigUtil.recoverTypedSignature_v4({
|
||||||
data: JSON.parse(
|
data: JSON.parse(
|
||||||
buildMsgParams(msg.encryptionPublicKey, "0x" + bufToHex(msg.ethAddress))
|
buildMsgParams(msg.encryptionPublicKey, "0x" + bytesToHex(msg.ethAddress))
|
||||||
),
|
),
|
||||||
sig: "0x" + bufToHex(msg.signature),
|
sig: "0x" + bytesToHex(msg.signature),
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("Recovered", recovered);
|
console.log("Recovered", recovered);
|
||||||
console.log("ethAddress", "0x" + bufToHex(msg.ethAddress));
|
console.log("ethAddress", "0x" + bytesToHex(msg.ethAddress));
|
||||||
|
|
||||||
return equalByteArrays(recovered, msg.ethAddress);
|
return equalByteArrays(recovered, msg.ethAddress);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {
|
||||||
} from "@material-ui/core";
|
} from "@material-ui/core";
|
||||||
import React, { ChangeEvent, useState, KeyboardEvent } from "react";
|
import React, { ChangeEvent, useState, KeyboardEvent } from "react";
|
||||||
import { Waku, WakuMessage } from "js-waku";
|
import { Waku, WakuMessage } from "js-waku";
|
||||||
import { bufToHex, hexToBuf } from "js-waku/lib/utils";
|
import { bytesToHex, hexToBytes } from "js-waku/lib/utils";
|
||||||
import { PrivateMessage } from "./wire";
|
import { PrivateMessage } from "./wire";
|
||||||
import { PrivateMessageContentTopic } from "../waku";
|
import { PrivateMessageContentTopic } from "../waku";
|
||||||
import * as sigUtil from "eth-sig-util";
|
import * as sigUtil from "eth-sig-util";
|
||||||
|
@ -111,7 +111,7 @@ async function encodeEncryptedWakuMessage(
|
||||||
address: string
|
address: string
|
||||||
): Promise<WakuMessage> {
|
): Promise<WakuMessage> {
|
||||||
const privateMessage = new PrivateMessage({
|
const privateMessage = new PrivateMessage({
|
||||||
toAddress: hexToBuf(address),
|
toAddress: hexToBytes(address),
|
||||||
message: message,
|
message: message,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ async function encodeEncryptedWakuMessage(
|
||||||
|
|
||||||
const encObj = sigUtil.encrypt(
|
const encObj = sigUtil.encrypt(
|
||||||
Buffer.from(publicKey).toString("base64"),
|
Buffer.from(publicKey).toString("base64"),
|
||||||
{ data: bufToHex(payload) },
|
{ data: bytesToHex(payload) },
|
||||||
"x25519-xsalsa20-poly1305"
|
"x25519-xsalsa20-poly1305"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { Waku, WakuMessage } from "js-waku";
|
||||||
import { PrivateMessage, PublicKeyMessage } from "./messaging/wire";
|
import { PrivateMessage, PublicKeyMessage } from "./messaging/wire";
|
||||||
import { validatePublicKeyMessage } from "./crypto";
|
import { validatePublicKeyMessage } from "./crypto";
|
||||||
import { Message } from "./messaging/Messages";
|
import { Message } from "./messaging/Messages";
|
||||||
import { bufToHex, equalByteArrays } from "js-waku/lib/utils";
|
import { bytesToHex, equalByteArrays } from "js-waku/lib/utils";
|
||||||
|
|
||||||
export const PublicKeyContentTopic =
|
export const PublicKeyContentTopic =
|
||||||
"/eth-pm-wallet/1/encryption-public-key/proto";
|
"/eth-pm-wallet/1/encryption-public-key/proto";
|
||||||
|
@ -44,7 +44,7 @@ export function handlePublicKeyMessage(
|
||||||
if (res) {
|
if (res) {
|
||||||
setPublicKeys((prevPks: Map<string, Uint8Array>) => {
|
setPublicKeys((prevPks: Map<string, Uint8Array>) => {
|
||||||
prevPks.set(
|
prevPks.set(
|
||||||
bufToHex(publicKeyMsg.ethAddress),
|
bytesToHex(publicKeyMsg.ethAddress),
|
||||||
publicKeyMsg.encryptionPublicKey
|
publicKeyMsg.encryptionPublicKey
|
||||||
);
|
);
|
||||||
return new Map(prevPks);
|
return new Map(prevPks);
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import "@ethersproject/shims";
|
import "@ethersproject/shims";
|
||||||
|
|
||||||
import { PublicKeyMessage } from "./messaging/wire";
|
import { PublicKeyMessage } from "./messaging/wire";
|
||||||
import { hexToBuf, equalByteArrays, bufToHex } from "js-waku/lib/utils";
|
import { hexToBytes, equalByteArrays, bytesToHex } from "js-waku/lib/utils";
|
||||||
import { generatePrivateKey, getPublicKey } from "js-waku";
|
import { generatePrivateKey, getPublicKey } from "js-waku";
|
||||||
import * as sigUtil from "eth-sig-util";
|
import * as sigUtil from "eth-sig-util";
|
||||||
import { PublicKeyContentTopic } from "./waku";
|
import { PublicKeyContentTopic } from "./waku";
|
||||||
import { keccak256 } from "ethers/lib/utils";
|
import { keccak256 } from "ethers/lib/utils";
|
||||||
|
|
||||||
export const PublicKeyMessageEncryptionKey = hexToBuf(
|
export const PublicKeyMessageEncryptionKey = hexToBytes(
|
||||||
keccak256(Buffer.from(PublicKeyContentTopic, "utf-8"))
|
keccak256(Buffer.from(PublicKeyContentTopic, "utf-8"))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -49,8 +49,8 @@ export async function createPublicKeyMessage(
|
||||||
|
|
||||||
return new PublicKeyMessage({
|
return new PublicKeyMessage({
|
||||||
encryptionPublicKey: encryptionPublicKey,
|
encryptionPublicKey: encryptionPublicKey,
|
||||||
ethAddress: hexToBuf(address),
|
ethAddress: hexToBytes(address),
|
||||||
signature: hexToBuf(signature),
|
signature: hexToBytes(signature),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ function buildMsgParams(encryptionPublicKey: Uint8Array, fromAddress: string) {
|
||||||
version: "1",
|
version: "1",
|
||||||
},
|
},
|
||||||
message: {
|
message: {
|
||||||
encryptionPublicKey: bufToHex(encryptionPublicKey),
|
encryptionPublicKey: bytesToHex(encryptionPublicKey),
|
||||||
ownerAddress: fromAddress,
|
ownerAddress: fromAddress,
|
||||||
},
|
},
|
||||||
// Refers to the keys of the *types* object below.
|
// Refers to the keys of the *types* object below.
|
||||||
|
@ -100,7 +100,7 @@ export async function signEncryptionKey(
|
||||||
|
|
||||||
console.log("TYPED SIGNED:" + JSON.stringify(result));
|
console.log("TYPED SIGNED:" + JSON.stringify(result));
|
||||||
|
|
||||||
return hexToBuf(result);
|
return hexToBytes(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -109,13 +109,13 @@ export async function signEncryptionKey(
|
||||||
export function validatePublicKeyMessage(msg: PublicKeyMessage): boolean {
|
export function validatePublicKeyMessage(msg: PublicKeyMessage): boolean {
|
||||||
const recovered = sigUtil.recoverTypedSignature_v4({
|
const recovered = sigUtil.recoverTypedSignature_v4({
|
||||||
data: JSON.parse(
|
data: JSON.parse(
|
||||||
buildMsgParams(msg.encryptionPublicKey, "0x" + bufToHex(msg.ethAddress))
|
buildMsgParams(msg.encryptionPublicKey, "0x" + bytesToHex(msg.ethAddress))
|
||||||
),
|
),
|
||||||
sig: "0x" + bufToHex(msg.signature),
|
sig: "0x" + bytesToHex(msg.signature),
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("Recovered", recovered);
|
console.log("Recovered", recovered);
|
||||||
console.log("ethAddress", "0x" + bufToHex(msg.ethAddress));
|
console.log("ethAddress", "0x" + bytesToHex(msg.ethAddress));
|
||||||
|
|
||||||
return equalByteArrays(recovered, msg.ethAddress);
|
return equalByteArrays(recovered, msg.ethAddress);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { KeyPair } from "../crypto";
|
import { KeyPair } from "../crypto";
|
||||||
import { bufToHex, hexToBuf } from "js-waku/lib/utils";
|
import { bytesToHex, hexToBytes } from "js-waku/lib/utils";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save keypair to storage, encrypted with password
|
* Save keypair to storage, encrypted with password
|
||||||
|
@ -11,9 +11,9 @@ export async function saveKeyPairToStorage(
|
||||||
const { salt, iv, cipher } = await encryptKey(EncryptionKeyPair, password);
|
const { salt, iv, cipher } = await encryptKey(EncryptionKeyPair, password);
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
salt: bufToHex(salt),
|
salt: bytesToHex(salt),
|
||||||
iv: bufToHex(iv),
|
iv: bytesToHex(iv),
|
||||||
cipher: bufToHex(cipher),
|
cipher: bytesToHex(cipher),
|
||||||
};
|
};
|
||||||
|
|
||||||
localStorage.setItem("cipherEncryptionKeyPair", JSON.stringify(data));
|
localStorage.setItem("cipherEncryptionKeyPair", JSON.stringify(data));
|
||||||
|
@ -29,9 +29,9 @@ export async function loadKeyPairFromStorage(
|
||||||
if (!str) return;
|
if (!str) return;
|
||||||
const data = JSON.parse(str);
|
const data = JSON.parse(str);
|
||||||
|
|
||||||
const salt = hexToBuf(data.salt);
|
const salt = hexToBytes(data.salt);
|
||||||
const iv = hexToBuf(data.iv);
|
const iv = hexToBytes(data.iv);
|
||||||
const cipher = hexToBuf(data.cipher);
|
const cipher = hexToBytes(data.cipher);
|
||||||
|
|
||||||
return await decryptKey(salt, iv, cipher, password);
|
return await decryptKey(salt, iv, cipher, password);
|
||||||
}
|
}
|
||||||
|
@ -96,9 +96,9 @@ async function encryptKey(encryptionKeyPair: KeyPair, password: string) {
|
||||||
* Derive a key from a password, and use the key to decrypt the cipher key pair.
|
* Derive a key from a password, and use the key to decrypt the cipher key pair.
|
||||||
*/
|
*/
|
||||||
async function decryptKey(
|
async function decryptKey(
|
||||||
salt: Buffer,
|
salt: Uint8Array,
|
||||||
iv: Buffer,
|
iv: Uint8Array,
|
||||||
cipherKeyPair: Buffer,
|
cipherKeyPair: Uint8Array,
|
||||||
password: string
|
password: string
|
||||||
): Promise<KeyPair | undefined> {
|
): Promise<KeyPair | undefined> {
|
||||||
const keyMaterial = await getKeyMaterial(password);
|
const keyMaterial = await getKeyMaterial(password);
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {
|
||||||
} from "@material-ui/core";
|
} from "@material-ui/core";
|
||||||
import React, { ChangeEvent, useState, KeyboardEvent } from "react";
|
import React, { ChangeEvent, useState, KeyboardEvent } from "react";
|
||||||
import { Waku, WakuMessage } from "js-waku";
|
import { Waku, WakuMessage } from "js-waku";
|
||||||
import { hexToBuf } from "js-waku/lib/utils";
|
import { hexToBytes } from "js-waku/lib/utils";
|
||||||
import { PrivateMessage } from "./wire";
|
import { PrivateMessage } from "./wire";
|
||||||
import { PrivateMessageContentTopic } from "../waku";
|
import { PrivateMessageContentTopic } from "../waku";
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ async function encodeEncryptedWakuMessage(
|
||||||
address: string
|
address: string
|
||||||
): Promise<WakuMessage> {
|
): Promise<WakuMessage> {
|
||||||
const privateMessage = new PrivateMessage({
|
const privateMessage = new PrivateMessage({
|
||||||
toAddress: hexToBuf(address),
|
toAddress: hexToBytes(address),
|
||||||
message: message,
|
message: message,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { Waku, WakuMessage } from "js-waku";
|
||||||
import { PrivateMessage, PublicKeyMessage } from "./messaging/wire";
|
import { PrivateMessage, PublicKeyMessage } from "./messaging/wire";
|
||||||
import { validatePublicKeyMessage } from "./crypto";
|
import { validatePublicKeyMessage } from "./crypto";
|
||||||
import { Message } from "./messaging/Messages";
|
import { Message } from "./messaging/Messages";
|
||||||
import { bufToHex, equalByteArrays } from "js-waku/lib/utils";
|
import { bytesToHex, equalByteArrays } from "js-waku/lib/utils";
|
||||||
|
|
||||||
export const PublicKeyContentTopic = "/eth-pm/1/public-key/proto";
|
export const PublicKeyContentTopic = "/eth-pm/1/public-key/proto";
|
||||||
export const PrivateMessageContentTopic = "/eth-pm/1/private-message/proto";
|
export const PrivateMessageContentTopic = "/eth-pm/1/private-message/proto";
|
||||||
|
@ -42,7 +42,7 @@ export function handlePublicKeyMessage(
|
||||||
if (res) {
|
if (res) {
|
||||||
setter((prevPks: Map<string, Uint8Array>) => {
|
setter((prevPks: Map<string, Uint8Array>) => {
|
||||||
prevPks.set(
|
prevPks.set(
|
||||||
bufToHex(publicKeyMsg.ethAddress),
|
bytesToHex(publicKeyMsg.ethAddress),
|
||||||
publicKeyMsg.encryptionPublicKey
|
publicKeyMsg.encryptionPublicKey
|
||||||
);
|
);
|
||||||
return new Map(prevPks);
|
return new Map(prevPks);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { bufToHex } from "../utils";
|
import { bytesToHex } from "../utils";
|
||||||
|
|
||||||
import { NodeId } from "./types";
|
import { NodeId } from "./types";
|
||||||
|
|
||||||
|
@ -6,5 +6,5 @@ export function createNodeId(buffer: Buffer): NodeId {
|
||||||
if (buffer.length !== 32) {
|
if (buffer.length !== 32) {
|
||||||
throw new Error("NodeId must be 32 bytes in length");
|
throw new Error("NodeId must be 32 bytes in length");
|
||||||
}
|
}
|
||||||
return bufToHex(buffer);
|
return bytesToHex(buffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { assert, expect } from "chai";
|
||||||
import { Multiaddr } from "multiaddr";
|
import { Multiaddr } from "multiaddr";
|
||||||
import PeerId from "peer-id";
|
import PeerId from "peer-id";
|
||||||
|
|
||||||
import { bufToHex } from "../utils";
|
import { bytesToHex } from "../utils";
|
||||||
|
|
||||||
import { ERR_INVALID_ID } from "./constants";
|
import { ERR_INVALID_ID } from "./constants";
|
||||||
import { ENR } from "./enr";
|
import { ENR } from "./enr";
|
||||||
|
@ -31,8 +31,8 @@ describe("ENR", function () {
|
||||||
const txt = enr.encodeTxt(keypair.privateKey);
|
const txt = enr.encodeTxt(keypair.privateKey);
|
||||||
expect(txt.slice(0, 4)).to.be.equal("enr:");
|
expect(txt.slice(0, 4)).to.be.equal("enr:");
|
||||||
const enr2 = ENR.decodeTxt(txt);
|
const enr2 = ENR.decodeTxt(txt);
|
||||||
expect(bufToHex(enr2.signature as Buffer)).to.be.equal(
|
expect(bytesToHex(enr2.signature as Buffer)).to.be.equal(
|
||||||
bufToHex(enr.signature as Buffer)
|
bytesToHex(enr.signature as Buffer)
|
||||||
);
|
);
|
||||||
const multiaddr = enr2.getLocationMultiaddr("udp")!;
|
const multiaddr = enr2.getLocationMultiaddr("udp")!;
|
||||||
expect(multiaddr.toString()).to.be.equal("/ip4/18.223.219.100/udp/9000");
|
expect(multiaddr.toString()).to.be.equal("/ip4/18.223.219.100/udp/9000");
|
||||||
|
@ -56,7 +56,7 @@ describe("ENR", function () {
|
||||||
const enr = ENR.decodeTxt(txt);
|
const enr = ENR.decodeTxt(txt);
|
||||||
const eth2 = enr.get("eth2") as Buffer;
|
const eth2 = enr.get("eth2") as Buffer;
|
||||||
expect(eth2).to.not.be.undefined;
|
expect(eth2).to.not.be.undefined;
|
||||||
expect(bufToHex(eth2)).to.be.equal("f6775d0700000113ffffffffffff1f00");
|
expect(bytesToHex(eth2)).to.be.equal("f6775d0700000113ffffffffffff1f00");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should decode valid ENR with multiaddrs successfully [shared test vector]", () => {
|
it("should decode valid ENR with multiaddrs successfully [shared test vector]", () => {
|
||||||
|
|
|
@ -2,6 +2,8 @@ import { keccak256, Message } from "js-sha3";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert input to a Buffer.
|
* Convert input to a Buffer.
|
||||||
|
*
|
||||||
|
* @deprecated Use `hexToBytes` instead.
|
||||||
*/
|
*/
|
||||||
export function hexToBuf(hex: string | Buffer | Uint8Array): Buffer {
|
export function hexToBuf(hex: string | Buffer | Uint8Array): Buffer {
|
||||||
if (typeof hex === "string") {
|
if (typeof hex === "string") {
|
||||||
|
@ -11,36 +13,66 @@ export function hexToBuf(hex: string | Buffer | Uint8Array): Buffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert input to a byte array.
|
||||||
|
*/
|
||||||
|
export function hexToBytes(hex: string | Uint8Array): Uint8Array {
|
||||||
|
if (typeof hex === "string") {
|
||||||
|
const _hex = hex.replace(/^0x/i, "");
|
||||||
|
const bytes = [];
|
||||||
|
for (let c = 0; c < _hex.length; c += 2)
|
||||||
|
bytes.push(parseInt(_hex.substring(c, c + 2), 16));
|
||||||
|
|
||||||
|
return new Uint8Array(bytes);
|
||||||
|
}
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert input to hex string (no `0x` prefix).
|
* Convert input to hex string (no `0x` prefix).
|
||||||
|
*
|
||||||
|
* @deprecated Use `bytesToHex` instead.
|
||||||
*/
|
*/
|
||||||
export function bufToHex(buf: Uint8Array | Buffer | ArrayBuffer): string {
|
export function bufToHex(buf: Uint8Array | Buffer | ArrayBuffer): string {
|
||||||
const _buf = Buffer.from(buf);
|
const _buf = Buffer.from(buf);
|
||||||
return _buf.toString("hex");
|
return _buf.toString("hex");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert byte array to hex string (no `0x` prefix).
|
||||||
|
*/
|
||||||
|
export function bytesToHex(bytes: Uint8Array): string {
|
||||||
|
const hex = [];
|
||||||
|
for (let i = 0; i < bytes.length; i++) {
|
||||||
|
const current = bytes[i] < 0 ? bytes[i] + 256 : bytes[i];
|
||||||
|
hex.push((current >>> 4).toString(16));
|
||||||
|
hex.push((current & 0xf).toString(16));
|
||||||
|
}
|
||||||
|
return hex.join("");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare both inputs, return true if they represent the same byte array.
|
* Compare both inputs, return true if they represent the same byte array.
|
||||||
*/
|
*/
|
||||||
export function equalByteArrays(
|
export function equalByteArrays(
|
||||||
a: Uint8Array | Buffer | string,
|
a: Uint8Array | string,
|
||||||
b: Uint8Array | Buffer | string
|
b: Uint8Array | string
|
||||||
): boolean {
|
): boolean {
|
||||||
let aBuf: Buffer;
|
let _a: string;
|
||||||
let bBuf: Buffer;
|
let _b: string;
|
||||||
if (typeof a === "string") {
|
if (typeof a === "string") {
|
||||||
aBuf = hexToBuf(a);
|
_a = a.replace(/^0x/i, "").toLowerCase();
|
||||||
} else {
|
} else {
|
||||||
aBuf = Buffer.from(a);
|
_a = bytesToHex(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof b === "string") {
|
if (typeof b === "string") {
|
||||||
bBuf = hexToBuf(b);
|
_b = b.replace(/^0x/i, "").toLowerCase();
|
||||||
} else {
|
} else {
|
||||||
bBuf = Buffer.from(b);
|
_b = bytesToHex(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
return aBuf.compare(bBuf) === 0;
|
return _a === _b;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,13 +2,14 @@ import { expect } from "chai";
|
||||||
import debug from "debug";
|
import debug from "debug";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
bytesToUtf8,
|
||||||
makeLogFileName,
|
makeLogFileName,
|
||||||
NimWaku,
|
NimWaku,
|
||||||
NOISE_KEY_1,
|
NOISE_KEY_1,
|
||||||
WakuRelayMessage,
|
WakuRelayMessage,
|
||||||
} from "../../test_utils";
|
} from "../../test_utils";
|
||||||
import { delay } from "../../test_utils/delay";
|
import { delay } from "../../test_utils/delay";
|
||||||
import { hexToBuf } from "../utils";
|
import { hexToBytes } from "../utils";
|
||||||
import { Protocols, Waku } from "../waku";
|
import { Protocols, Waku } from "../waku";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -90,8 +91,8 @@ describe("Waku Message [node only]", function () {
|
||||||
|
|
||||||
dbg("Ask nim-waku to generate asymmetric key pair");
|
dbg("Ask nim-waku to generate asymmetric key pair");
|
||||||
const keyPair = await nimWaku.getAsymmetricKeyPair();
|
const keyPair = await nimWaku.getAsymmetricKeyPair();
|
||||||
const privateKey = hexToBuf(keyPair.privateKey);
|
const privateKey = hexToBytes(keyPair.privateKey);
|
||||||
const publicKey = hexToBuf(keyPair.publicKey);
|
const publicKey = hexToBytes(keyPair.publicKey);
|
||||||
|
|
||||||
const messageText = "This is a message I am going to encrypt";
|
const messageText = "This is a message I am going to encrypt";
|
||||||
dbg("Encrypt message");
|
dbg("Encrypt message");
|
||||||
|
@ -116,7 +117,7 @@ describe("Waku Message [node only]", function () {
|
||||||
|
|
||||||
dbg("Check message content");
|
dbg("Check message content");
|
||||||
expect(msgs[0].contentTopic).to.equal(message.contentTopic);
|
expect(msgs[0].contentTopic).to.equal(message.contentTopic);
|
||||||
expect(hexToBuf(msgs[0].payload).toString("utf-8")).to.equal(messageText);
|
expect(bytesToUtf8(hexToBytes(msgs[0].payload))).to.equal(messageText);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("JS decrypts nim message [symmetric, no signature]", async function () {
|
it("JS decrypts nim message [symmetric, no signature]", async function () {
|
||||||
|
@ -177,7 +178,7 @@ describe("Waku Message [node only]", function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(msgs[0].contentTopic).to.equal(message.contentTopic);
|
expect(msgs[0].contentTopic).to.equal(message.contentTopic);
|
||||||
expect(hexToBuf(msgs[0].payload).toString("utf-8")).to.equal(messageText);
|
expect(bytesToUtf8(hexToBytes(msgs[0].payload))).to.equal(messageText);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,7 +5,7 @@ import * as ecies from "ecies-geth";
|
||||||
import { keccak256 } from "js-sha3";
|
import { keccak256 } from "js-sha3";
|
||||||
import * as secp256k1 from "secp256k1";
|
import * as secp256k1 from "secp256k1";
|
||||||
|
|
||||||
import { hexToBuf } from "../utils";
|
import { hexToBytes } from "../utils";
|
||||||
|
|
||||||
import { IvSize, symmetric, SymmetricKeySize } from "./symmetric";
|
import { IvSize, symmetric, SymmetricKeySize } from "./symmetric";
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ export function clearEncode(
|
||||||
if (sigPrivKey) {
|
if (sigPrivKey) {
|
||||||
envelope[0] |= IsSignedMask;
|
envelope[0] |= IsSignedMask;
|
||||||
const hash = keccak256(envelope);
|
const hash = keccak256(envelope);
|
||||||
const s = secp256k1.ecdsaSign(hexToBuf(hash), sigPrivKey);
|
const s = secp256k1.ecdsaSign(hexToBytes(hash), sigPrivKey);
|
||||||
envelope = Buffer.concat([envelope, s.signature, Buffer.from([s.recid])]);
|
envelope = Buffer.concat([envelope, s.signature, Buffer.from([s.recid])]);
|
||||||
sig = {
|
sig = {
|
||||||
signature: Buffer.from(s.signature),
|
signature: Buffer.from(s.signature),
|
||||||
|
@ -116,7 +116,7 @@ export async function encryptAsymmetric(
|
||||||
data: Uint8Array | Buffer,
|
data: Uint8Array | Buffer,
|
||||||
publicKey: Uint8Array | Buffer | string
|
publicKey: Uint8Array | Buffer | string
|
||||||
): Promise<Uint8Array> {
|
): Promise<Uint8Array> {
|
||||||
return ecies.encrypt(hexToBuf(publicKey), Buffer.from(data));
|
return ecies.encrypt(Buffer.from(hexToBytes(publicKey)), Buffer.from(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -148,7 +148,11 @@ export async function encryptSymmetric(
|
||||||
const iv = symmetric.generateIv();
|
const iv = symmetric.generateIv();
|
||||||
|
|
||||||
// Returns `cipher | tag`
|
// Returns `cipher | tag`
|
||||||
const cipher = await symmetric.encrypt(iv, hexToBuf(key), Buffer.from(data));
|
const cipher = await symmetric.encrypt(
|
||||||
|
iv,
|
||||||
|
Buffer.from(hexToBytes(key)),
|
||||||
|
Buffer.from(data)
|
||||||
|
);
|
||||||
return Buffer.concat([cipher, Buffer.from(iv)]);
|
return Buffer.concat([cipher, Buffer.from(iv)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +174,7 @@ export async function decryptSymmetric(
|
||||||
const cipher = data.slice(0, ivStart);
|
const cipher = data.slice(0, ivStart);
|
||||||
const iv = data.slice(ivStart);
|
const iv = data.slice(ivStart);
|
||||||
|
|
||||||
return symmetric.decrypt(iv, hexToBuf(key), cipher);
|
return symmetric.decrypt(iv, Buffer.from(hexToBytes(key)), cipher);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -250,7 +254,7 @@ function ecRecoverPubKey(messageHash: string, signature: Buffer): Uint8Array {
|
||||||
return secp256k1.ecdsaRecover(
|
return secp256k1.ecdsaRecover(
|
||||||
signature.slice(0, 64),
|
signature.slice(0, 64),
|
||||||
recovery,
|
recovery,
|
||||||
hexToBuf(messageHash),
|
hexToBytes(messageHash),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { InMessage } from "libp2p-interfaces/src/pubsub";
|
||||||
import { SignaturePolicy } from "libp2p-interfaces/src/pubsub/signature-policy";
|
import { SignaturePolicy } from "libp2p-interfaces/src/pubsub/signature-policy";
|
||||||
import PeerId from "peer-id";
|
import PeerId from "peer-id";
|
||||||
|
|
||||||
import { hexToBuf } from "../utils";
|
import { hexToBytes } from "../utils";
|
||||||
import { CreateOptions, DefaultPubSubTopic } from "../waku";
|
import { CreateOptions, DefaultPubSubTopic } from "../waku";
|
||||||
import { DecryptionMethod, WakuMessage } from "../waku_message";
|
import { DecryptionMethod, WakuMessage } from "../waku_message";
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ export class WakuRelay extends Gossipsub {
|
||||||
key: Uint8Array | string,
|
key: Uint8Array | string,
|
||||||
options?: { method?: DecryptionMethod; contentTopics?: string[] }
|
options?: { method?: DecryptionMethod; contentTopics?: string[] }
|
||||||
): void {
|
): void {
|
||||||
this.decryptionKeys.set(hexToBuf(key), options ?? {});
|
this.decryptionKeys.set(hexToBytes(key), options ?? {});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -145,7 +145,7 @@ export class WakuRelay extends Gossipsub {
|
||||||
* Strings must be in hex format.
|
* Strings must be in hex format.
|
||||||
*/
|
*/
|
||||||
deleteDecryptionKey(key: Uint8Array | string): void {
|
deleteDecryptionKey(key: Uint8Array | string): void {
|
||||||
this.decryptionKeys.delete(hexToBuf(key));
|
this.decryptionKeys.delete(hexToBytes(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,7 +8,7 @@ import PeerId from "peer-id";
|
||||||
|
|
||||||
import { HistoryResponse_Error } from "../../proto";
|
import { HistoryResponse_Error } from "../../proto";
|
||||||
import { getPeersForProtocol, selectRandomPeer } from "../select_peer";
|
import { getPeersForProtocol, selectRandomPeer } from "../select_peer";
|
||||||
import { hexToBuf } from "../utils";
|
import { hexToBytes } from "../utils";
|
||||||
import { DefaultPubSubTopic } from "../waku";
|
import { DefaultPubSubTopic } from "../waku";
|
||||||
import { DecryptionMethod, WakuMessage } from "../waku_message";
|
import { DecryptionMethod, WakuMessage } from "../waku_message";
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@ export class WakuStore {
|
||||||
if (opts.decryptionKeys) {
|
if (opts.decryptionKeys) {
|
||||||
opts.decryptionKeys.forEach((key) => {
|
opts.decryptionKeys.forEach((key) => {
|
||||||
decryptionKeys.push({
|
decryptionKeys.push({
|
||||||
key: hexToBuf(key),
|
key: hexToBytes(key),
|
||||||
contentTopics: contentTopics.length ? contentTopics : undefined,
|
contentTopics: contentTopics.length ? contentTopics : undefined,
|
||||||
method: undefined,
|
method: undefined,
|
||||||
});
|
});
|
||||||
|
@ -276,7 +276,7 @@ export class WakuStore {
|
||||||
key: Uint8Array | string,
|
key: Uint8Array | string,
|
||||||
options?: { method?: DecryptionMethod; contentTopics?: string[] }
|
options?: { method?: DecryptionMethod; contentTopics?: string[] }
|
||||||
): void {
|
): void {
|
||||||
this.decryptionKeys.set(hexToBuf(key), options ?? {});
|
this.decryptionKeys.set(hexToBytes(key), options ?? {});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -286,7 +286,7 @@ export class WakuStore {
|
||||||
* Strings must be in hex format.
|
* Strings must be in hex format.
|
||||||
*/
|
*/
|
||||||
deleteDecryptionKey(key: Uint8Array | string): void {
|
deleteDecryptionKey(key: Uint8Array | string): void {
|
||||||
this.decryptionKeys.delete(hexToBuf(key));
|
this.decryptionKeys.delete(hexToBytes(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -9,3 +9,4 @@ export * from "./async_fs";
|
||||||
export * from "./constants";
|
export * from "./constants";
|
||||||
export * from "./log_file";
|
export * from "./log_file";
|
||||||
export * from "./nim_waku";
|
export * from "./nim_waku";
|
||||||
|
export * from "./utf8";
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
|
|
||||||
import { argsToArray, bufToHex, defaultArgs, strToHex } from "./nim_waku";
|
import { argsToArray, bytesToHex, defaultArgs, strToHex } from "./nim_waku";
|
||||||
|
|
||||||
describe("nim_waku", () => {
|
describe("nim_waku", () => {
|
||||||
it("Correctly serialized arguments", function () {
|
it("Correctly serialized arguments", function () {
|
||||||
|
@ -37,7 +37,7 @@ describe("nim_waku", () => {
|
||||||
]);
|
]);
|
||||||
const expected = "5468697320697320616e207574662d3820737472696e672e";
|
const expected = "5468697320697320616e207574662d3820737472696e672e";
|
||||||
|
|
||||||
const actual = bufToHex(buf);
|
const actual = bytesToHex(buf);
|
||||||
expect(actual).to.deep.equal(expected);
|
expect(actual).to.deep.equal(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { Multiaddr, multiaddr } from "multiaddr";
|
||||||
import PeerId from "peer-id";
|
import PeerId from "peer-id";
|
||||||
import portfinder from "portfinder";
|
import portfinder from "portfinder";
|
||||||
|
|
||||||
import { hexToBuf } from "../lib/utils";
|
import { hexToBytes } from "../lib/utils";
|
||||||
import { DefaultPubSubTopic } from "../lib/waku";
|
import { DefaultPubSubTopic } from "../lib/waku";
|
||||||
import { WakuMessage } from "../lib/waku_message";
|
import { WakuMessage } from "../lib/waku_message";
|
||||||
import * as proto from "../proto/waku/v2/message";
|
import * as proto from "../proto/waku/v2/message";
|
||||||
|
@ -203,7 +203,7 @@ export class NimWaku {
|
||||||
}
|
}
|
||||||
|
|
||||||
const rpcMessage = {
|
const rpcMessage = {
|
||||||
payload: bufToHex(message.payload),
|
payload: bytesToHex(message.payload),
|
||||||
contentTopic: message.contentTopic,
|
contentTopic: message.contentTopic,
|
||||||
timestamp,
|
timestamp,
|
||||||
};
|
};
|
||||||
|
@ -258,7 +258,7 @@ export class NimWaku {
|
||||||
return this.rpcCall<boolean>("post_waku_v2_private_v1_asymmetric_message", [
|
return this.rpcCall<boolean>("post_waku_v2_private_v1_asymmetric_message", [
|
||||||
pubSubTopic ? pubSubTopic : DefaultPubSubTopic,
|
pubSubTopic ? pubSubTopic : DefaultPubSubTopic,
|
||||||
message,
|
message,
|
||||||
"0x" + bufToHex(publicKey),
|
"0x" + bytesToHex(publicKey),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,18 +272,18 @@ export class NimWaku {
|
||||||
"get_waku_v2_private_v1_asymmetric_messages",
|
"get_waku_v2_private_v1_asymmetric_messages",
|
||||||
[
|
[
|
||||||
pubSubTopic ? pubSubTopic : DefaultPubSubTopic,
|
pubSubTopic ? pubSubTopic : DefaultPubSubTopic,
|
||||||
"0x" + bufToHex(privateKey),
|
"0x" + bytesToHex(privateKey),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getSymmetricKey(): Promise<Buffer> {
|
async getSymmetricKey(): Promise<Uint8Array> {
|
||||||
this.checkProcess();
|
this.checkProcess();
|
||||||
|
|
||||||
return this.rpcCall<string>(
|
return this.rpcCall<string>(
|
||||||
"get_waku_v2_private_v1_symmetric_key",
|
"get_waku_v2_private_v1_symmetric_key",
|
||||||
[]
|
[]
|
||||||
).then(hexToBuf);
|
).then(hexToBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
async postSymmetricMessage(
|
async postSymmetricMessage(
|
||||||
|
@ -300,7 +300,7 @@ export class NimWaku {
|
||||||
return this.rpcCall<boolean>("post_waku_v2_private_v1_symmetric_message", [
|
return this.rpcCall<boolean>("post_waku_v2_private_v1_symmetric_message", [
|
||||||
pubSubTopic ? pubSubTopic : DefaultPubSubTopic,
|
pubSubTopic ? pubSubTopic : DefaultPubSubTopic,
|
||||||
message,
|
message,
|
||||||
"0x" + bufToHex(symKey),
|
"0x" + bytesToHex(symKey),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,7 +312,10 @@ export class NimWaku {
|
||||||
|
|
||||||
return await this.rpcCall<WakuRelayMessage[]>(
|
return await this.rpcCall<WakuRelayMessage[]>(
|
||||||
"get_waku_v2_private_v1_symmetric_messages",
|
"get_waku_v2_private_v1_symmetric_messages",
|
||||||
[pubSubTopic ? pubSubTopic : DefaultPubSubTopic, "0x" + bufToHex(symKey)]
|
[
|
||||||
|
pubSubTopic ? pubSubTopic : DefaultPubSubTopic,
|
||||||
|
"0x" + bytesToHex(symKey),
|
||||||
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,7 +419,7 @@ export function strToHex(str: string): string {
|
||||||
return hex;
|
return hex;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function bufToHex(buffer: Uint8Array): string {
|
export function bytesToHex(buffer: Uint8Array): string {
|
||||||
return Array.prototype.map
|
return Array.prototype.map
|
||||||
.call(buffer, (x) => ("00" + x.toString(16)).slice(-2))
|
.call(buffer, (x) => ("00" + x.toString(16)).slice(-2))
|
||||||
.join("");
|
.join("");
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
// Thanks https://gist.github.com/pascaldekloe/62546103a1576803dade9269ccf76330
|
||||||
|
export function bytesToUtf8(bytes: Uint8Array): string {
|
||||||
|
let i = 0,
|
||||||
|
s = "";
|
||||||
|
while (i < bytes.length) {
|
||||||
|
let c = bytes[i++];
|
||||||
|
if (c > 127) {
|
||||||
|
if (c > 191 && c < 224) {
|
||||||
|
if (i >= bytes.length)
|
||||||
|
throw new Error("UTF-8 decode: incomplete 2-byte sequence");
|
||||||
|
c = ((c & 31) << 6) | (bytes[i++] & 63);
|
||||||
|
} else if (c > 223 && c < 240) {
|
||||||
|
if (i + 1 >= bytes.length)
|
||||||
|
throw new Error("UTF-8 decode: incomplete 3-byte sequence");
|
||||||
|
c = ((c & 15) << 12) | ((bytes[i++] & 63) << 6) | (bytes[i++] & 63);
|
||||||
|
} else if (c > 239 && c < 248) {
|
||||||
|
if (i + 2 >= bytes.length)
|
||||||
|
throw new Error("UTF-8 decode: incomplete 4-byte sequence");
|
||||||
|
c =
|
||||||
|
((c & 7) << 18) |
|
||||||
|
((bytes[i++] & 63) << 12) |
|
||||||
|
((bytes[i++] & 63) << 6) |
|
||||||
|
(bytes[i++] & 63);
|
||||||
|
} else
|
||||||
|
throw new Error(
|
||||||
|
"UTF-8 decode: unknown multi byte start 0x" +
|
||||||
|
c.toString(16) +
|
||||||
|
" at index " +
|
||||||
|
(i - 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (c <= 0xffff) s += String.fromCharCode(c);
|
||||||
|
else if (c <= 0x10ffff) {
|
||||||
|
c -= 0x10000;
|
||||||
|
s += String.fromCharCode((c >> 10) | 0xd800);
|
||||||
|
s += String.fromCharCode((c & 0x3ff) | 0xdc00);
|
||||||
|
} else
|
||||||
|
throw new Error(
|
||||||
|
"UTF-8 decode: code point 0x" + c.toString(16) + " exceeds UTF-16 reach"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
Loading…
Reference in New Issue