From dc2c09bd41bf6f47a995da5299c72689686e3e6b Mon Sep 17 00:00:00 2001 From: Franck Royer Date: Thu, 1 Jul 2021 11:52:07 +1000 Subject: [PATCH] Change public key message encoding to protobuf --- examples/eth-dm/package-lock.json | 174 +++++++++++++++++++++ examples/eth-dm/package.json | 1 + examples/eth-dm/src/BroadcastPublicKey.tsx | 8 +- examples/eth-dm/src/InitWaku.tsx | 17 +- examples/eth-dm/src/crypto.ts | 25 ++- examples/eth-dm/src/messaging/wire.ts | 54 ++++++- 6 files changed, 261 insertions(+), 18 deletions(-) diff --git a/examples/eth-dm/package-lock.json b/examples/eth-dm/package-lock.json index 18ca7dca48..7e42b0bdf3 100644 --- a/examples/eth-dm/package-lock.json +++ b/examples/eth-dm/package-lock.json @@ -19,6 +19,7 @@ "ethers": "^5.2.0", "fontsource-roboto": "^4.0.0", "js-waku": "../../build/main", + "protobufjs": "^6.11.2", "react": "^17.0.2", "react-dom": "^17.0.2", "react-scripts": "4.0.3", @@ -3705,6 +3706,60 @@ "node": ">= 8" } }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, "node_modules/@rollup/plugin-node-resolve": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz", @@ -4204,6 +4259,11 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" }, + "node_modules/@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, "node_modules/@types/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", @@ -14838,6 +14898,11 @@ "url": "https://tidelift.com/funding/github/npm/loglevel" } }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -17973,6 +18038,31 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/protobufjs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", + "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -26672,6 +26762,60 @@ } } }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, "@rollup/plugin-node-resolve": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz", @@ -27034,6 +27178,11 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=" }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, "@types/minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", @@ -35215,6 +35364,11 @@ "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==" }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -37707,6 +37861,26 @@ } } }, + "protobufjs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", + "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + } + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", diff --git a/examples/eth-dm/package.json b/examples/eth-dm/package.json index 1c7cb88c86..e28a570b3f 100644 --- a/examples/eth-dm/package.json +++ b/examples/eth-dm/package.json @@ -16,6 +16,7 @@ "ethers": "^5.2.0", "fontsource-roboto": "^4.0.0", "js-waku": "../../build/main", + "protobufjs": "^6.11.2", "react": "^17.0.2", "react-dom": "^17.0.2", "react-scripts": "4.0.3", diff --git a/examples/eth-dm/src/BroadcastPublicKey.tsx b/examples/eth-dm/src/BroadcastPublicKey.tsx index f73e4cf9a4..8c4484276b 100644 --- a/examples/eth-dm/src/BroadcastPublicKey.tsx +++ b/examples/eth-dm/src/BroadcastPublicKey.tsx @@ -1,7 +1,7 @@ import { Button } from '@material-ui/core'; import React, { useState } from 'react'; import { createPublicKeyMessage, KeyPair } from './crypto'; -import { encode, PublicKeyMessage } from './messaging/wire'; +import { PublicKeyMessage } from './messaging/wire'; import { WakuMessage, Waku } from 'js-waku'; import { Signer } from '@ethersproject/abstract-signer'; import { PublicKeyContentTopic } from './InitWaku'; @@ -56,7 +56,9 @@ export default function BroadcastPublicKey({ ); } -function encodePublicKeyWakuMessage(ethDmMsg: PublicKeyMessage): WakuMessage { - const payload = encode(ethDmMsg); +function encodePublicKeyWakuMessage( + publicKeyMessage: PublicKeyMessage +): WakuMessage { + const payload = publicKeyMessage.encode(); return WakuMessage.fromBytes(payload, PublicKeyContentTopic); } diff --git a/examples/eth-dm/src/InitWaku.tsx b/examples/eth-dm/src/InitWaku.tsx index ad1a56b649..a1c5b07708 100644 --- a/examples/eth-dm/src/InitWaku.tsx +++ b/examples/eth-dm/src/InitWaku.tsx @@ -1,10 +1,15 @@ import { Dispatch, SetStateAction, useEffect } from 'react'; import { Environment, getStatusFleetNodes, Waku, WakuMessage } from 'js-waku'; -import { decode, DirectMessage, PublicKeyMessage } from './messaging/wire'; +import { + bytesToHexStr, + decode, + DirectMessage, + PublicKeyMessage, +} from './messaging/wire'; import { decryptMessage, KeyPair, validatePublicKeyMessage } from './crypto'; import { Message } from './messaging/Messages'; -export const PublicKeyContentTopic = '/eth-dm/1/public-key/json'; +export const PublicKeyContentTopic = '/eth-dm/1/public-key/proto'; export const DirectMessageContentTopic = '/eth-dm/1/direct-message/json'; interface Props { @@ -115,13 +120,15 @@ function handlePublicKeyMessage( msg: WakuMessage ) { if (!msg.payload) return; - const publicKeyMsg: PublicKeyMessage = decode(msg.payload); - if (publicKeyMsg.ethDmPublicKey === myPublicKey) return; + const publicKeyMsg = PublicKeyMessage.decode(msg.payload); + const ethDmPublicKey = bytesToHexStr(publicKeyMsg.ethDmPublicKey); + if (ethDmPublicKey === myPublicKey) return; + const res = validatePublicKeyMessage(publicKeyMsg); console.log(`Public Key Message Received, valid: ${res}`, publicKeyMsg); setter((prevPks: Map) => { - prevPks.set(publicKeyMsg.ethAddress, publicKeyMsg.ethDmPublicKey); + prevPks.set(bytesToHexStr(publicKeyMsg.ethAddress), ethDmPublicKey); return new Map(prevPks); }); } diff --git a/examples/eth-dm/src/crypto.ts b/examples/eth-dm/src/crypto.ts index b357efcfef..ac9480c908 100644 --- a/examples/eth-dm/src/crypto.ts +++ b/examples/eth-dm/src/crypto.ts @@ -3,7 +3,11 @@ import '@ethersproject/shims'; import * as EthCrypto from 'eth-crypto'; import { ethers } from 'ethers'; import { Signer } from '@ethersproject/abstract-signer'; -import { DirectMessage, PublicKeyMessage } from './messaging/wire'; +import { + bytesToHexStr, + DirectMessage, + PublicKeyMessage, +} from './messaging/wire'; export interface KeyPair { privateKey: string; @@ -29,10 +33,19 @@ export async function createPublicKeyMessage( ethDmPublicKey: string ): Promise { const ethAddress = await web3Signer.getAddress(); - const sig = await web3Signer.signMessage( + const signature = await web3Signer.signMessage( formatPublicKeyForSignature(ethDmPublicKey) ); - return { ethDmPublicKey, ethAddress, sig }; + + const bytesEthDmPublicKey = Buffer.from(ethDmPublicKey, 'hex'); + const bytesEthAddress = Buffer.from(ethAddress.replace(/0x/, ''), 'hex'); + const bytesSignature = Buffer.from(signature.replace(/0x/, ''), 'hex'); + + return new PublicKeyMessage({ + ethDmPublicKey: bytesEthDmPublicKey, + ethAddress: bytesEthAddress, + signature: bytesSignature, + }); } /** @@ -41,10 +54,10 @@ export async function createPublicKeyMessage( export function validatePublicKeyMessage(msg: PublicKeyMessage): boolean { try { const sigAddress = ethers.utils.verifyMessage( - formatPublicKeyForSignature(msg.ethDmPublicKey), - msg.sig + formatPublicKeyForSignature(bytesToHexStr(msg.ethDmPublicKey)), + msg.signature ); - return sigAddress === msg.ethAddress; + return sigAddress === bytesToHexStr(msg.ethAddress); } catch (e) { return false; } diff --git a/examples/eth-dm/src/messaging/wire.ts b/examples/eth-dm/src/messaging/wire.ts index e76cbc8a89..803bc04b1c 100644 --- a/examples/eth-dm/src/messaging/wire.ts +++ b/examples/eth-dm/src/messaging/wire.ts @@ -1,12 +1,58 @@ import * as EthCrypto from 'eth-crypto'; +import * as protobuf from 'protobufjs/light'; + +export interface PublicKeyMessagePayload { + ethDmPublicKey: Uint8Array; + ethAddress: Uint8Array; + signature: Uint8Array; +} + +const Root = protobuf.Root, + Type = protobuf.Type, + Field = protobuf.Field; /** * Message used to communicate the Eth-Dm public key linked to a given Ethereum account */ -export interface PublicKeyMessage { - ethDmPublicKey: string; - ethAddress: string; - sig: string; +export class PublicKeyMessage { + private static Type = new Type('PublicKeyMessage') + .add(new Field('PublicKeyMessage', 1, 'bytes')) + .add(new Field('ethAddress', 2, 'bytes')) + .add(new Field('signature', 3, 'bytes')); + private static Root = new Root() + .define('messages') + .add(PublicKeyMessage.Type); + + constructor(public payload: PublicKeyMessagePayload) {} + + public encode(): Uint8Array { + const message = PublicKeyMessage.Type.create(this.payload); + return PublicKeyMessage.Type.encode(message).finish(); + } + + public static decode(bytes: Uint8Array | Buffer): PublicKeyMessage { + const payload = PublicKeyMessage.Type.decode( + bytes + ) as unknown as PublicKeyMessagePayload; + return new PublicKeyMessage(payload); + } + + get ethDmPublicKey(): Uint8Array { + return this.payload.ethDmPublicKey; + } + + get ethAddress(): Uint8Array { + return this.payload.ethAddress; + } + + get signature(): Uint8Array { + return this.payload.signature; + } +} + +export function bytesToHexStr(bytes: Uint8Array): string { + const buf = new Buffer(bytes); + return buf.toString('hex'); } /**