From 484fbcab1b25072b4c45f496a88d361fc9479be4 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Tue, 7 Jul 2020 10:56:26 +0200 Subject: [PATCH] use bearssl rng throughout (#265) * use bearssl rng throughout * seeder can fail * imports and exports * modules, sigh * one more try * move var * even fewer thread vars * remove out-of-date genrated files --- .gitignore | 1 + eth/keys.nim | 53 +- eth/p2p.nim | 10 +- eth/p2p/auth.nim | 108 +-- eth/p2p/discovery.nim | 6 +- eth/p2p/discoveryv5/discovery_db.nim | 2 +- eth/p2p/discoveryv5/encoding.nim | 48 +- eth/p2p/discoveryv5/enr.nim | 2 +- eth/p2p/discoveryv5/protocol.nim | 88 +-- eth/p2p/ecies.nim | 14 +- eth/p2p/kademlia.nim | 17 +- eth/p2p/private/p2p_types.nim | 3 +- eth/p2p/rlpx.nim | 12 +- eth/p2p/rlpx.nim.generated.nim | 196 ------ .../rlpx_protocols/whisper/whisper_types.nim | 33 +- eth/p2p/rlpx_protocols/whisper_protocol.nim | 7 +- .../whisper_protocol.nim.generated.nim | 662 ------------------ tests/fuzzing/rlpx/thunk.nim | 5 +- tests/keyfile/test_keyfile.nim | 4 +- tests/keys/test_keys.nim | 26 +- tests/p2p/discv5_test_helper.nim | 24 +- tests/p2p/p2p_test_helper.nim | 18 +- tests/p2p/test_auth.nim | 48 +- tests/p2p/test_crypt.nim | 18 +- tests/p2p/test_discoveryv5.nim | 77 +- tests/p2p/test_discv5_encoding.nim | 8 +- tests/p2p/test_ecies.nim | 8 +- tests/p2p/test_enr.nim | 6 +- tests/p2p/test_protocol_handlers.nim | 14 +- tests/p2p/test_rlpx_thunk.nim | 13 +- tests/p2p/test_routing_table.nim | 79 ++- tests/p2p/test_shh.nim | 58 +- tests/p2p/test_shh_connect.nim | 17 +- 33 files changed, 433 insertions(+), 1252 deletions(-) delete mode 100644 eth/p2p/rlpx.nim.generated.nim delete mode 100644 eth/p2p/rlpx_protocols/whisper_protocol.nim.generated.nim diff --git a/.gitignore b/.gitignore index ca15e92..08154e9 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ build/ *.la *.exe *.dll +*.generated.nim diff --git a/eth/keys.nim b/eth/keys.nim index 95943a1..17813f7 100644 --- a/eth/keys.nim +++ b/eth/keys.nim @@ -15,13 +15,13 @@ {.push raises: [Defect].} import - secp256k1, + secp256k1, bearssl, nimcrypto/hash, nimcrypto/keccak, stew/[byteutils, objects, results], strformat from nimcrypto/utils import burnMem -export secp256k1, results +export secp256k1, results, bearssl const KeyLength* = SkEcdhRawSecretSize - 1 @@ -46,12 +46,31 @@ type SharedSecret* = object data*: array[KeyLength, byte] - KeyPair* = object - seckey*: PrivateKey - pubkey*: PublicKey + KeyPair* = distinct SkKeyPair -proc random*(T: type PrivateKey): SkResult[T] = - SkSecretKey.random().mapConvert(T) +template pubkey*(v: KeyPair): PublicKey = PublicKey(SkKeyPair(v).pubkey) +template seckey*(v: KeyPair): PrivateKey = PrivateKey(SkKeyPair(v).seckey) + +proc newRng*(): ref BrHmacDrbgContext = + # You should only create one instance of the RNG per application / library + # Ref is used so that it can be shared between components + # TODO consider moving to bearssl + var seeder = brPrngSeederSystem(nil) + if seeder == nil: + return nil + + var rng = (ref BrHmacDrbgContext)() + brHmacDrbgInit(addr rng[], addr sha256Vtable, nil, 0) + if seeder(addr rng.vtable) == 0: + return nil + rng + +proc random*(T: type PrivateKey, rng: var BrHmacDrbgContext): T = + let rngPtr = unsafeAddr rng # doesn't escape + proc callRng(data: var openArray[byte]) = + brHmacDrbgGenerate(rngPtr[], data) + + T(SkSecretKey.random(callRng)) func fromRaw*(T: type PrivateKey, data: openArray[byte]): SkResult[T] = SkSecretKey.fromRaw(data).mapConvert(T) @@ -87,12 +106,16 @@ func toRaw*(pubkey: PublicKey): array[RawPublicKeySize, byte] = func toRawCompressed*(pubkey: PublicKey): array[33, byte] {.borrow.} -proc random*(T: type KeyPair): SkResult[T] = - let tmp = ? SkKeypair.random() - ok(T(seckey: PrivateKey(tmp.seckey), pubkey: PublicKey(tmp.pubkey))) +proc random*(T: type KeyPair, rng: var BrHmacDrbgContext): T = + let seckey = SkSecretKey(PrivateKey.random(rng)) + KeyPair(SkKeyPair( + seckey: seckey, + pubkey: seckey.toPublicKey() + )) func toKeyPair*(seckey: PrivateKey): KeyPair = - KeyPair(seckey: seckey, pubkey: seckey.toPublicKey()) + KeyPair(SkKeyPair( + seckey: SkSecretKey(seckey), pubkey: SkSecretKey(seckey).toPublicKey())) func fromRaw*(T: type Signature, data: openArray[byte]): SkResult[T] = SkRecoverableSignature.fromRaw(data).mapConvert(T) @@ -192,28 +215,28 @@ func sign*(seckey: PrivateKey, msg: SkMessage): Signature = func sign*(seckey: PrivateKey, msg: openArray[byte]): Signature = let hash = keccak256.digest(msg) - sign(seckey, hash) + sign(seckey, SkMessage(hash.data)) func signNR*(seckey: PrivateKey, msg: SkMessage): SignatureNR = SignatureNR(sign(SkSecretKey(seckey), msg)) func signNR*(seckey: PrivateKey, msg: openArray[byte]): SignatureNR = let hash = keccak256.digest(msg) - signNR(seckey, hash) + signNR(seckey, SkMessage(hash.data)) func recover*(sig: Signature, msg: SkMessage): SkResult[PublicKey] = recover(SkRecoverableSignature(sig), msg).mapConvert(PublicKey) func recover*(sig: Signature, msg: openArray[byte]): SkResult[PublicKey] = let hash = keccak256.digest(msg) - recover(sig, hash) + recover(sig, SkMessage(hash.data)) func verify*(sig: SignatureNR, msg: SkMessage, key: PublicKey): bool = verify(SkSignature(sig), msg, SkPublicKey(key)) func verify*(sig: SignatureNR, msg: openArray[byte], key: PublicKey): bool = let hash = keccak256.digest(msg) - verify(sig, hash, key) + verify(sig, SkMessage(hash.data), key) func ecdhRaw*(seckey: PrivateKey, pubkey: PublicKey): SharedSecret = let tmp = ecdhRaw(SkSecretKey(seckey), SkPublicKey(pubkey)) diff --git a/eth/p2p.nim b/eth/p2p.nim index 0ca3a29..17fad0a 100644 --- a/eth/p2p.nim +++ b/eth/p2p.nim @@ -9,7 +9,7 @@ # import - tables, algorithm, random, + tables, algorithm, random, bearssl, chronos, chronos/timer, chronicles, eth/keys, eth/common/eth_types, eth/p2p/[kademlia, discovery, enode, peer_pool, rlpx], @@ -38,7 +38,12 @@ proc newEthereumNode*(keys: KeyPair, clientId = "nim-eth-p2p/0.2.0", # TODO: read this value from nimble somehow addAllCapabilities = true, useCompression: bool = false, - minPeers = 10): EthereumNode = + minPeers = 10, + rng = newRng()): EthereumNode = + + if rng == nil: # newRng could fail + raise (ref CatchableError)(msg: "Cannot initialize RNG") + new result result.keys = keys result.networkId = networkId @@ -47,6 +52,7 @@ proc newEthereumNode*(keys: KeyPair, result.capabilities.newSeq 0 result.address = address result.connectionState = ConnectionState.None + result.rng = rng when useSnappy: result.protocolVersion = if useCompression: devp2pSnappyVersion diff --git a/eth/p2p/auth.nim b/eth/p2p/auth.nim index b93b747..73118e0 100644 --- a/eth/p2p/auth.nim +++ b/eth/p2p/auth.nim @@ -12,7 +12,7 @@ {.push raises: [Defect].} -import eth/[keys, rlp], nimcrypto +import eth/[keys, rlp], nimcrypto/[rijndael, keccak, utils], bearssl import ecies import stew/[byteutils, endians2, objects, results] @@ -54,7 +54,6 @@ type Eip8 ## Flag indicates that EIP-8 handshake is used AuthError* = enum - RandomError = "auth: could not obtain random data" EcdhError = "auth: ECDH shared secret could not be calculated" BufferOverrun = "auth: buffer overrun" SignatureError = "auth: signature could not be obtained" @@ -95,7 +94,8 @@ proc mapErrTo[T, E](r: Result[T, E], v: static AuthError): AuthResult[T] = r.mapErr(proc (e: E): AuthError = v) proc tryInit*( - T: type Handshake, host: KeyPair, flags: set[HandshakeFlag] = {Initiator}, + T: type Handshake, rng: var BrHmacDrbgContext, host: KeyPair, + flags: set[HandshakeFlag] = {Initiator}, version: uint8 = SupportedRlpxVersion): AuthResult[T] = ## Create new `Handshake` object. @@ -103,16 +103,14 @@ proc tryInit*( initiatorNonce: Nonce responderNonce: Nonce expectedLength: int - ephemeral = ? KeyPair.random().mapErrTo(RandomError) + ephemeral = KeyPair.random(rng) if Initiator in flags: expectedLength = AckMessageV4Length - if randomBytes(initiatorNonce) != len(initiatorNonce): - return err(RandomError) + brHmacDrbgGenerate(rng, initiatorNonce) else: expectedLength = AuthMessageV4Length - if randomBytes(responderNonce) != len(responderNonce): - return err(RandomError) + brHmacDrbgGenerate(rng, responderNonce) return ok(T( version: version, @@ -125,6 +123,7 @@ proc tryInit*( )) proc authMessagePreEIP8(h: var Handshake, + rng: var BrHmacDrbgContext, pubkey: PublicKey, output: var openarray[byte], outlen: var int, @@ -137,12 +136,11 @@ proc authMessagePreEIP8(h: var Handshake, let header = cast[ptr AuthMessageV4](addr buffer[0]) var secret = ecdhRaw(h.host.seckey, pubkey) - let xornonce = secret.data xor h.initiatorNonce + secret.data = secret.data xor h.initiatorNonce + let signature = sign(h.ephemeral.seckey, SkMessage(secret.data)) secret.clear() - let signature = sign(h.ephemeral.seckey, SkMessage(data: xornonce)) - h.remoteHPubkey = pubkey header.signature = signature.toRaw() header.keyhash = keccak256.digest(h.ephemeral.pubkey.toRaw()).data @@ -152,7 +150,7 @@ proc authMessagePreEIP8(h: var Handshake, if encrypt: if len(output) < AuthMessageV4Length: return err(BufferOverrun) - if eciesEncrypt(buffer, output, h.remoteHPubkey).isErr: + if eciesEncrypt(rng, buffer, output, h.remoteHPubkey).isErr: return err(EciesError) outlen = AuthMessageV4Length else: @@ -164,6 +162,7 @@ proc authMessagePreEIP8(h: var Handshake, ok() proc authMessageEIP8(h: var Handshake, + rng: var BrHmacDrbgContext, pubkey: PublicKey, output: var openarray[byte], outlen: var int, @@ -172,50 +171,49 @@ proc authMessageEIP8(h: var Handshake, ## Create EIP8 authentication message. var buffer: array[PlainAuthMessageMaxEIP8, byte] - padsize: byte + padsize: array[1, byte] doAssert(EIP8 in h.flags) outlen = 0 - var - secret = ecdhRaw(h.host.seckey, pubkey) - xornonce = secret.data xor h.initiatorNonce + var secret = ecdhRaw(h.host.seckey, pubkey) + secret.data = secret.data xor h.initiatorNonce + + let signature = sign(h.ephemeral.seckey, SkMessage(secret.data)) secret.clear() - let signature = sign(h.ephemeral.seckey, SkMessage(data: xornonce)) - h.remoteHPubkey = pubkey var payload = rlp.encodeList(signature.toRaw(), h.host.pubkey.toRaw(), h.initiatorNonce, [byte(h.version)]) doAssert(len(payload) == PlainAuthMessageEIP8Length) - let pencsize = eciesEncryptedLength(len(payload)) + let + pencsize = eciesEncryptedLength(len(payload)) + while true: - if randomBytes(addr padsize, 1) != 1: - return err(RandomError) - if int(padsize) > (AuthMessageV4Length - (pencsize + 2)): + brHmacDrbgGenerate(rng, padsize) + if int(padsize[0]) > (AuthMessageV4Length - (pencsize + 2)): break # It is possible to make packet size constant by uncommenting this line # padsize = 24 - let wosize = pencsize + int(padsize) + let wosize = pencsize + int(padsize[0]) let fullsize = wosize + 2 - if randomBytes(toa(buffer, PlainAuthMessageEIP8Length, - int(padsize))) != int(padsize): - return err(RandomError) + brHmacDrbgGenerate( + rng, toa(buffer, PlainAuthMessageEIP8Length, int(padsize[0]))) if encrypt: copyMem(addr buffer[0], addr payload[0], len(payload)) if len(output) < fullsize: return err(BufferOverrun) let wosizeBE = uint16(wosize).toBytesBE() output[0..<2] = wosizeBE - if eciesEncrypt(toa(buffer, 0, len(payload) + int(padsize)), + if eciesEncrypt(rng, toa(buffer, 0, len(payload) + int(padsize[0])), toa(output, 2, wosize), pubkey, toa(output, 0, 2)).isErr: return err(EciesError) outlen = fullsize else: - let plainsize = len(payload) + int(padsize) + let plainsize = len(payload) + int(padsize[0]) if len(output) < plainsize: return err(BufferOverrun) copyMem(addr output[0], addr buffer[0], plainsize) @@ -224,6 +222,7 @@ proc authMessageEIP8(h: var Handshake, ok() proc ackMessagePreEIP8(h: var Handshake, + rng: var BrHmacDrbgContext, output: var openarray[byte], outlen: var int, flag: byte = 0, @@ -238,7 +237,7 @@ proc ackMessagePreEIP8(h: var Handshake, if encrypt: if len(output) < AckMessageV4Length: return err(BufferOverrun) - if eciesEncrypt(buffer, output, h.remoteHPubkey).isErr: + if eciesEncrypt(rng, buffer, output, h.remoteHPubkey).isErr: return err(EciesError) outlen = AckMessageV4Length else: @@ -250,6 +249,7 @@ proc ackMessagePreEIP8(h: var Handshake, ok() proc ackMessageEIP8(h: var Handshake, + rng: var BrHmacDrbgContext, output: var openarray[byte], outlen: var int, flag: byte = 0, @@ -257,7 +257,7 @@ proc ackMessageEIP8(h: var Handshake, ## Create EIP8 authentication ack message. var buffer: array[PlainAckMessageMaxEIP8, byte] - padsize: byte + padsize: array[1, byte] doAssert(EIP8 in h.flags) var payload = rlp.encodeList(h.ephemeral.pubkey.toRaw(), h.responderNonce, @@ -266,30 +266,29 @@ proc ackMessageEIP8(h: var Handshake, outlen = 0 let pencsize = eciesEncryptedLength(len(payload)) while true: - if randomBytes(addr padsize, 1) != 1: - return err(RandomError) - if int(padsize) > (AckMessageV4Length - (pencsize + 2)): + brHmacDrbgGenerate(rng, padsize) + if int(padsize[0]) > (AckMessageV4Length - (pencsize + 2)): break # It is possible to make packet size constant by uncommenting this line # padsize = 0 - let wosize = pencsize + int(padsize) + let wosize = pencsize + int(padsize[0]) let fullsize = wosize + 2 - if int(padsize) > 0: - if randomBytes(toa(buffer, PlainAckMessageEIP8Length, - int(padsize))) != int(padsize): - return err(RandomError) + if int(padsize[0]) > 0: + brHmacDrbgGenerate( + rng, toa(buffer, PlainAckMessageEIP8Length, int(padsize[0]))) + copyMem(addr buffer[0], addr payload[0], len(payload)) if encrypt: if len(output) < fullsize: return err(BufferOverrun) output[0..<2] = uint16(wosize).toBytesBE() - if eciesEncrypt(toa(buffer, 0, len(payload) + int(padsize)), + if eciesEncrypt(rng, toa(buffer, 0, len(payload) + int(padsize[0])), toa(output, 2, wosize), h.remoteHPubkey, toa(output, 0, 2)).isErr: return err(EciesError) outlen = fullsize else: - let plainsize = len(payload) + int(padsize) + let plainsize = len(payload) + int(padsize[0]) if len(output) < plainsize: return err(BufferOverrun) copyMem(addr output[0], addr buffer[0], plainsize) @@ -311,26 +310,28 @@ template ackSize*(h: Handshake, encrypt: bool = true): int = else: if encrypt: (AckMessageV4Length) else: (PlainAckMessageV4Length) -proc authMessage*(h: var Handshake, pubkey: PublicKey, +proc authMessage*(h: var Handshake, rng: var BrHmacDrbgContext, + pubkey: PublicKey, output: var openarray[byte], outlen: var int, flag: byte = 0, encrypt: bool = true): AuthResult[void] = ## Create new AuthMessage for specified `pubkey` and store it inside ## of `output`, size of generated AuthMessage will stored in `outlen`. if EIP8 in h.flags: - authMessageEIP8(h, pubkey, output, outlen, flag, encrypt) + authMessageEIP8(h, rng, pubkey, output, outlen, flag, encrypt) else: - authMessagePreEIP8(h, pubkey, output, outlen, flag, encrypt) + authMessagePreEIP8(h, rng, pubkey, output, outlen, flag, encrypt) -proc ackMessage*(h: var Handshake, output: var openarray[byte], +proc ackMessage*(h: var Handshake, rng: var BrHmacDrbgContext, + output: var openarray[byte], outlen: var int, flag: byte = 0, encrypt: bool = true): AuthResult[void] = ## Create new AckMessage and store it inside of `output`, size of generated ## AckMessage will stored in `outlen`. if EIP8 in h.flags: - ackMessageEIP8(h, output, outlen, flag, encrypt) + ackMessageEIP8(h, rng, output, outlen, flag, encrypt) else: - ackMessagePreEIP8(h, output, outlen, flag, encrypt) + ackMessagePreEIP8(h, rng, output, outlen, flag, encrypt) proc decodeAuthMessageV4(h: var Handshake, m: openarray[byte]): AuthResult[void] = ## Decodes V4 AuthMessage. @@ -347,12 +348,12 @@ proc decodeAuthMessageV4(h: var Handshake, m: openarray[byte]): AuthResult[void] signature = ? Signature.fromRaw(header.signature).mapErrTo(SignatureError) var secret = ecdhRaw(h.host.seckey, pubkey) - let xornonce = secret.data xor header.nonce + secret.data = secret.data xor header.nonce + var recovered = recover(signature, SkMessage(secret.data)) secret.clear() - h.remoteEPubkey = - ? recover(signature, SkMessage(data: xornonce)).mapErrTo(SignatureError) + h.remoteEPubkey = ? recovered.mapErrTo(SignatureError) h.initiatorNonce = header.nonce h.remoteHPubkey = pubkey @@ -392,13 +393,12 @@ proc decodeAuthMessageEip8(h: var Handshake, m: openarray[byte]): AuthResult[voi nonce = toArray(KeyLength, nonceBr) var secret = ecdhRaw(h.host.seckey, pubkey) + secret.data = secret.data xor nonce - let xornonce = nonce xor secret.data + let recovered = recover(signature, SkMessage(secret.data)) secret.clear() - h.remoteEPubkey = - ? recover(signature, SkMessage(data: xornonce)).mapErrTo(SignatureError) - + h.remoteEPubkey = ? recovered.mapErrTo(SignatureError) h.initiatorNonce = nonce h.remoteHPubkey = pubkey h.version = versionBr[0] @@ -520,7 +520,7 @@ proc getSecrets*( mac1 = ctx0.finish() secret.macKey = mac1.data - burnMem(shsec) + clear(shsec) # egress-mac = keccak256(mac-secret ^ recipient-nonce || auth-sent-init) diff --git a/eth/p2p/discovery.nim b/eth/p2p/discovery.nim index 9a12abf..d4938a7 100644 --- a/eth/p2p/discovery.nim +++ b/eth/p2p/discovery.nim @@ -10,7 +10,7 @@ import times, - chronos, stint, nimcrypto, chronicles, + chronos, stint, nimcrypto/keccak, chronicles, bearssl, eth/[keys, rlp], kademlia, enode, stew/[objects, results] @@ -155,7 +155,7 @@ proc sendNeighbours*(d: DiscoveryProtocol, node: Node, neighbours: seq[Node]) = if nodes.len != 0: flush() proc newDiscoveryProtocol*(privKey: PrivateKey, address: Address, - bootstrapNodes: openarray[ENode] + bootstrapNodes: openarray[ENode], rng = newRng() ): DiscoveryProtocol = result.new() result.privKey = privKey @@ -163,7 +163,7 @@ proc newDiscoveryProtocol*(privKey: PrivateKey, address: Address, result.bootstrapNodes = newSeqOfCap[Node](bootstrapNodes.len) for n in bootstrapNodes: result.bootstrapNodes.add(newNode(n)) result.thisNode = newNode(privKey.toPublicKey(), address) - result.kademlia = newKademliaProtocol(result.thisNode, result) + result.kademlia = newKademliaProtocol(result.thisNode, result, rng = rng) proc recvPing(d: DiscoveryProtocol, node: Node, msgHash: MDigest[256]) {.inline.} = diff --git a/eth/p2p/discoveryv5/discovery_db.nim b/eth/p2p/discoveryv5/discovery_db.nim index 0f6131a..c2324d9 100644 --- a/eth/p2p/discoveryv5/discovery_db.nim +++ b/eth/p2p/discoveryv5/discovery_db.nim @@ -28,7 +28,7 @@ proc makeKey(id: NodeId, address: Address): array[keySize, byte] = of IpAddressFamily.IpV4: result[pos ..< pos+sizeof(address.ip.address_v4)] = address.ip.address_v4 of IpAddressFamily.IpV6: - result[pos..< pos+sizeof(address.ip.address_v6)] = address.ip.address_v6 + result[pos ..< pos+sizeof(address.ip.address_v6)] = address.ip.address_v6 pos.inc(sizeof(address.ip.address_v6)) result[pos ..< pos+sizeof(address.port)] = toBytes(address.port.uint16) diff --git a/eth/p2p/discoveryv5/encoding.nim b/eth/p2p/discoveryv5/encoding.nim index 0d30226..e423506 100644 --- a/eth/p2p/discoveryv5/encoding.nim +++ b/eth/p2p/discoveryv5/encoding.nim @@ -1,6 +1,6 @@ import std/[tables, options], nimcrypto, stint, chronicles, stew/results, - types, node, enr, hkdf, eth/[rlp, keys] + types, node, enr, hkdf, eth/[rlp, keys], bearssl export keys @@ -64,7 +64,7 @@ proc idNonceHash(nonce, ephkey: openarray[byte]): MDigest[256] = proc signIDNonce*(privKey: PrivateKey, idNonce, ephKey: openarray[byte]): SignatureNR = - signNR(privKey, idNonceHash(idNonce, ephKey)) + signNR(privKey, SkMessage(idNonceHash(idNonce, ephKey).data)) proc deriveKeys(n1, n2: NodeID, priv: PrivateKey, pub: PublicKey, idNonce: openarray[byte]): HandshakeSecrets = @@ -89,11 +89,12 @@ proc encryptGCM*(key, nonce, pt, authData: openarray[byte]): seq[byte] = ectx.getTag(result.toOpenArray(pt.len, result.high)) ectx.clear() -proc encodeAuthHeader*(c: Codec, +proc encodeAuthHeader*(rng: var BrHmacDrbgContext, + c: Codec, toId: NodeID, nonce: array[gcmNonceSize, byte], challenge: Whoareyou): - EncodeResult[(seq[byte], HandshakeSecrets)] = + (seq[byte], HandshakeSecrets) = var resp = AuthResponse(version: 5) let ln = c.localNode @@ -101,7 +102,7 @@ proc encodeAuthHeader*(c: Codec, if challenge.recordSeq < ln.record.seqNum: resp.record = ln.record - let ephKeys = ? KeyPair.random() + let ephKeys = KeyPair.random(rng) let signature = signIDNonce(c.privKey, challenge.idNonce, ephKeys.pubkey.toRaw) resp.signature = signature.toRaw @@ -117,7 +118,7 @@ proc encodeAuthHeader*(c: Codec, let header = AuthHeader(auth: nonce, idNonce: challenge.idNonce, scheme: authSchemeName, ephemeralKey: ephKeys.pubkey.toRaw, response: respEnc) - ok((rlp.encode(header), secrets)) + (rlp.encode(header), secrets) proc `xor`[N: static[int], T](a, b: array[N, T]): array[N, T] = for i in 0 .. a.high: @@ -130,15 +131,16 @@ proc packetTag(destNode, srcNode: NodeID): PacketTag = destidHash = sha256.digest(destId) result = srcId xor destidHash.data -proc encodePacket*(c: Codec, - toId: NodeID, - toAddr: Address, - message: openarray[byte], - challenge: Whoareyou): - EncodeResult[(seq[byte], array[gcmNonceSize, byte])] = +proc encodePacket*( + rng: var BrHmacDrbgContext, + c: Codec, + toId: NodeID, + toAddr: Address, + message: openarray[byte], + challenge: Whoareyou): + (seq[byte], array[gcmNonceSize, byte]) = var nonce: array[gcmNonceSize, byte] - if randomBytes(nonce) != nonce.len: - return err("Could not randomize bytes") + brHmacDrbgGenerate(rng, nonce) var headEnc: seq[byte] @@ -153,7 +155,7 @@ proc encodePacket*(c: Codec, discard c.db.loadKeys(toId, toAddr, readKey, writeKey) else: var secrets: HandshakeSecrets - (headEnc, secrets) = ? c.encodeAuthHeader(toId, nonce, challenge) + (headEnc, secrets) = encodeAuthHeader(rng, c, toId, nonce, challenge) writeKey = secrets.writeKey # TODO: is it safe to ignore the error here? @@ -165,7 +167,7 @@ proc encodePacket*(c: Codec, packet.add(tag) packet.add(headEnc) packet.add(encryptGCM(writeKey, nonce, message, tag)) - ok((packet, nonce)) + (packet, nonce) proc decryptGCM*(key: AesKey, nonce, ct, authData: openarray[byte]): Option[seq[byte]] = @@ -260,7 +262,7 @@ proc decodeAuthResp*(c: Codec, fromId: NodeId, head: AuthHeader, # Verify the id-nonce-sig let sig = ? SignatureNR.fromRaw(authResp.signature).mapErrTo(HandshakeError) let h = idNonceHash(head.idNonce, head.ephemeralKey) - if verify(sig, h, newNode.pubkey): + if verify(sig, SkMessage(h.data), newNode.pubkey): ok(secrets) else: err(HandshakeError) @@ -332,12 +334,12 @@ proc decodePacket*(c: var Codec, decodeMessage(message.get()) -proc newRequestId*(): Result[RequestId, cstring] = - var id: RequestId - if randomBytes(addr id, sizeof(id)) != sizeof(id): - err("Could not randomize bytes") - else: - ok(id) +proc init*(T: type RequestId, rng: var BrHmacDrbgContext): T = + var buf: array[sizeof(T), byte] + brHmacDrbgGenerate(rng, buf) + var id: T + copyMem(addr id, addr buf[0], sizeof(id)) + id proc numFields(T: typedesc): int = for k, v in fieldPairs(default(T)): inc result diff --git a/eth/p2p/discoveryv5/enr.nim b/eth/p2p/discoveryv5/enr.nim index 3c54252..a33ebbf 100644 --- a/eth/p2p/discoveryv5/enr.nim +++ b/eth/p2p/discoveryv5/enr.nim @@ -232,7 +232,7 @@ proc verifySignatureV4(r: Record, sigData: openarray[byte], content: seq[byte]): let sig = SignatureNR.fromRaw(sigData) if sig.isOk: var h = keccak256.digest(content) - return verify(sig[], h, publicKey.get) + return verify(sig[], SkMessage(h.data), publicKey.get) proc verifySignature(r: Record): bool {.raises: [RlpError, Defect].} = var rlp = rlpFromBytes(r.raw) diff --git a/eth/p2p/discoveryv5/protocol.nim b/eth/p2p/discoveryv5/protocol.nim index e37c260..abe2357 100644 --- a/eth/p2p/discoveryv5/protocol.nim +++ b/eth/p2p/discoveryv5/protocol.nim @@ -73,7 +73,7 @@ ## This might be a concern for mobile devices. import - std/[tables, sets, options, math, random], + std/[tables, sets, options, math, random], bearssl, stew/shims/net as stewNet, json_serialization/std/net, stew/[byteutils, endians2], chronicles, chronos, stint, eth/[rlp, keys, async_utils], types, encoding, node, routing_table, enr @@ -120,6 +120,7 @@ type lookupLoop: Future[void] revalidateLoop: Future[void] bootstrapRecords*: seq[Record] + rng*: ref BrHmacDrbgContext PendingRequest = object node: Node @@ -222,9 +223,7 @@ proc sendWhoareyou(d: Protocol, address: Address, toNode: NodeId, authTag: AuthTag): DiscResult[void] {.raises: [Exception, Defect].} = trace "sending who are you", to = $toNode, toAddress = $address let challenge = Whoareyou(authTag: authTag, recordSeq: 0) - - if randomBytes(challenge.idNonce) != challenge.idNonce.len: - return err("Could not randomize bytes") + brHmacDrbgGenerate(d.rng[], challenge.idNonce) # If there is already a handshake going on for this nodeid then we drop this # new one. Handshake will get cleaned up after `handshakeTimeout`. @@ -250,17 +249,18 @@ proc sendWhoareyou(d: Protocol, address: Address, toNode: NodeId, err("NodeId already has ongoing handshake") proc sendNodes(d: Protocol, toId: NodeId, toAddr: Address, reqId: RequestId, - nodes: openarray[Node]): DiscResult[void] = + nodes: openarray[Node]) = proc sendNodes(d: Protocol, toId: NodeId, toAddr: Address, - message: NodesMessage, reqId: RequestId): DiscResult[void] {.nimcall.} = - let (data, _) = ? d.codec.encodePacket(toId, toAddr, + message: NodesMessage, reqId: RequestId) {.nimcall.} = + let (data, _) = encodePacket( + d.rng[], d.codec, toId, toAddr, encodeMessage(message, reqId), challenge = nil) d.send(toAddr, data) - ok() if nodes.len == 0: # In case of 0 nodes, a reply is still needed - return d.sendNodes(toId, toAddr, NodesMessage(total: 1, enrs: @[]), reqId) + d.sendNodes(toId, toAddr, NodesMessage(total: 1, enrs: @[]), reqId) + return var message: NodesMessage # TODO: Do the total calculation based on the max UDP packet size we want to @@ -271,19 +271,14 @@ proc sendNodes(d: Protocol, toId: NodeId, toAddr: Address, reqId: RequestId, for i in 0 ..< nodes.len: message.enrs.add(nodes[i].record) if message.enrs.len == maxNodesPerMessage: - let res = d.sendNodes(toId, toAddr, message, reqId) - if res.isErr: # TODO: is there something nicer for this? - return res + d.sendNodes(toId, toAddr, message, reqId) message.enrs.setLen(0) if message.enrs.len != 0: - let res = d.sendNodes(toId, toAddr, message, reqId) - if res.isErr: # TODO: is there something nicer for this? - return res - ok() + d.sendNodes(toId, toAddr, message, reqId) proc handlePing(d: Protocol, fromId: NodeId, fromAddr: Address, - ping: PingMessage, reqId: RequestId): DiscResult[void] = + ping: PingMessage, reqId: RequestId) = let a = fromAddr var pong: PongMessage pong.enrSeq = ping.enrSeq @@ -292,14 +287,13 @@ proc handlePing(d: Protocol, fromId: NodeId, fromAddr: Address, of IpAddressFamily.IPv6: @(a.ip.address_v6) pong.port = a.port.uint16 - let (data, _) = ? d.codec.encodePacket(fromId, fromAddr, + let (data, _) = encodePacket(d.rng[], d.codec, fromId, fromAddr, encodeMessage(pong, reqId), challenge = nil) d.send(fromAddr, data) - ok() proc handleFindNode(d: Protocol, fromId: NodeId, fromAddr: Address, - fn: FindNodeMessage, reqId: RequestId): DiscResult[void] = + fn: FindNodeMessage, reqId: RequestId) = if fn.distance == 0: d.sendNodes(fromId, fromAddr, reqId, [d.localNode]) else: @@ -333,14 +327,8 @@ proc receive*(d: Protocol, a: Address, packet: openArray[byte]) {.gcsafe, let toNode = pr.node whoareyou.pubKey = toNode.pubkey # TODO: Yeah, rather ugly this. doAssert(toNode.address.isSome()) - let encoded = d.codec.encodePacket(toNode.id, toNode.address.get(), + let (data, _) = encodePacket(d.rng[], d.codec, toNode.id, toNode.address.get(), pr.message, challenge = whoareyou) - # TODO: Perhaps just expect here? Or raise Defect in `encodePacket`? - # if this occurs there is an issue with the system anyhow? - if encoded.isErr: - warn "Not enough randomness to encode packet" - return - let (data, _) = encoded[] d.send(toNode, data) else: debug "Timed out or unrequested WhoAreYou packet" @@ -366,11 +354,9 @@ proc receive*(d: Protocol, a: Address, packet: openArray[byte]) {.gcsafe, case message.kind of ping: - if d.handlePing(sender, a, message.ping, message.reqId).isErr: - debug "Sending Pong message failed" + d.handlePing(sender, a, message.ping, message.reqId) of findNode: - if d.handleFindNode(sender, a, message.findNode, message.reqId).isErr: - debug "Sending Nodes message failed" + d.handleFindNode(sender, a, message.findNode, message.reqId) else: var waiter: Future[Option[Message]] if d.awaitedMessages.take((sender, message.reqId), waiter): @@ -518,24 +504,22 @@ proc waitNodes(d: Protocol, fromNode: Node, reqId: RequestId): return err("Nodes message not received in time") proc sendMessage*[T: SomeMessage](d: Protocol, toNode: Node, m: T): - DiscResult[RequestId] {.raises: [Exception, Defect].} = + RequestId {.raises: [Exception, Defect].} = doAssert(toNode.address.isSome()) let - reqId = ? newRequestId() + reqId = RequestId.init(d.rng[]) message = encodeMessage(m, reqId) - (data, nonce) = ? d.codec.encodePacket(toNode.id, toNode.address.get(), + (data, nonce) = encodePacket(d.rng[], d.codec, toNode.id, toNode.address.get(), message, challenge = nil) d.registerRequest(toNode, message, nonce) d.send(toNode, data) - return ok(reqId) + return reqId proc ping*(d: Protocol, toNode: Node): Future[DiscResult[PongMessage]] {.async, raises: [Exception, Defect].} = let reqId = d.sendMessage(toNode, PingMessage(enrSeq: d.localNode.record.seqNum)) - if reqId.isErr: - return err(reqId.error) - let resp = await d.waitMessage(toNode, reqId[]) + let resp = await d.waitMessage(toNode, reqId) if resp.isSome() and resp.get().kind == pong: d.routingTable.setJustSeen(toNode) @@ -547,9 +531,7 @@ proc ping*(d: Protocol, toNode: Node): proc findNode*(d: Protocol, toNode: Node, distance: uint32): Future[DiscResult[seq[Node]]] {.async, raises: [Exception, Defect].} = let reqId = d.sendMessage(toNode, FindNodeMessage(distance: distance)) - if reqId.isErr: - return err(reqId.error) - let nodes = await d.waitNodes(toNode, reqId[]) + let nodes = await d.waitNodes(toNode, reqId) if nodes.isOk: var res = newSeq[Node]() @@ -632,15 +614,16 @@ proc lookup*(d: Protocol, target: NodeId): Future[seq[Node]] if result.len < BUCKET_SIZE: result.add(n) -proc lookupRandom*(d: Protocol): Future[DiscResult[seq[Node]]] +proc lookupRandom*(d: Protocol): Future[seq[Node]] {.async, raises:[Exception, Defect].} = ## Perform a lookup for a random target, return the closest n nodes to the ## target. Maximum value for n is `BUCKET_SIZE`. var id: NodeId - if randomBytes(addr id, sizeof(id)) != sizeof(id): - return err("Could not randomize bytes") + var buf: array[sizeof(id), byte] + brHmacDrbgGenerate(d.rng[], buf) + copyMem(addr id, addr buf[0], sizeof(id)) - return ok(await d.lookup(id)) + return await d.lookup(id) proc resolve*(d: Protocol, id: NodeId): Future[Option[Node]] {.async, raises: [Exception, Defect].} = @@ -700,11 +683,8 @@ proc lookupLoop(d: Protocol) {.async, raises: [Exception, Defect].} = trace "Discovered nodes in self lookup", nodes = $selfLookup while true: let randomLookup = await d.lookupRandom() - if randomLookup.isOK: - trace "Discovered nodes in random lookup", nodes = $randomLookup[] - trace "Total nodes in routing table", total = d.routingTable.len() - else: - trace "random lookup failed", err = randomLookup.error + trace "Discovered nodes in random lookup", nodes = $randomLookup + trace "Total nodes in routing table", total = d.routingTable.len() await sleepAsync(lookupInterval) except CancelledError: trace "lookupLoop canceled" @@ -713,7 +693,7 @@ proc newProtocol*(privKey: PrivateKey, db: Database, externalIp: Option[ValidIpAddress], tcpPort, udpPort: Port, localEnrFields: openarray[FieldPair] = [], bootstrapRecords: openarray[Record] = [], - bindIp = IPv4_any()): + bindIp = IPv4_any(), rng = newRng()): Protocol {.raises: [Defect].} = # TODO: Tried adding bindPort = udpPort as parameter but that gave # "Error: internal error: environment misses: udpPort" in nim-beacon-chain. @@ -725,6 +705,9 @@ proc newProtocol*(privKey: PrivateKey, db: Database, localEnrFields).expect("Properly intialized private key") node = newNode(enrRec).expect("Properly initialized node") + # TODO Consider whether this should be a Defect + doAssert rng != nil, "RNG initialization failed" + result = Protocol( privateKey: privKey, db: db, @@ -733,7 +716,8 @@ proc newProtocol*(privKey: PrivateKey, db: Database, whoareyouMagic: whoareyouMagic(node.id), idHash: sha256.digest(node.id.toByteArrayBE).data, codec: Codec(localNode: node, privKey: privKey, db: db), - bootstrapRecords: @bootstrapRecords) + bootstrapRecords: @bootstrapRecords, + rng: rng) result.routingTable.init(node, 5) diff --git a/eth/p2p/ecies.nim b/eth/p2p/ecies.nim index 4caed1e..0af94bd 100644 --- a/eth/p2p/ecies.nim +++ b/eth/p2p/ecies.nim @@ -12,7 +12,8 @@ {.push raises: [Defect].} -import eth/keys, nimcrypto/[rijndael, bcmode, hash, hmac, sysrand, sha2, utils] +import bearssl +import eth/keys, nimcrypto/[rijndael, bcmode, hash, hmac, sha2, utils] import stew/results export results @@ -23,7 +24,6 @@ const type EciesError* = enum BufferOverrun = "ecies: output buffer size is too small" - RandomError = "ecies: could not obtain random data" EcdhError = "ecies: ECDH shared secret could not be calculated" WrongHeader = "ecies: header is incorrect" IncorrectKey = "ecies: recovered public key is invalid" @@ -92,8 +92,8 @@ proc kdf*(data: openarray[byte]): array[KeyLength, byte] {.noInit.} = ctx.clear() # clean ctx copyMem(addr result[0], addr storage[0], KeyLength) -proc eciesEncrypt*(input: openarray[byte], output: var openarray[byte], - pubkey: PublicKey, +proc eciesEncrypt*(rng: var BrHmacDrbgContext, input: openarray[byte], + output: var openarray[byte], pubkey: PublicKey, sharedmac: openarray[byte] = emptyMac): EciesResult[void] = ## Encrypt data with ECIES method using given public key `pubkey`. ## ``input`` - input data @@ -110,11 +110,11 @@ proc eciesEncrypt*(input: openarray[byte], output: var openarray[byte], if len(output) < eciesEncryptedLength(len(input)): return err(BufferOverrun) - if randomBytes(iv) != aes128.sizeBlock: - return err(RandomError) + + brHmacDrbgGenerate(rng, iv) var - ephemeral = ? KeyPair.random().mapErrTo(RandomError) + ephemeral = KeyPair.random(rng) secret = ecdhRaw(ephemeral.seckey, pubkey) material = kdf(secret.data) diff --git a/eth/p2p/kademlia.nim b/eth/p2p/kademlia.nim index 4d288b1..bd3c70f 100644 --- a/eth/p2p/kademlia.nim +++ b/eth/p2p/kademlia.nim @@ -9,8 +9,8 @@ # import - tables, hashes, times, algorithm, sets, sequtils, random, - chronos, eth/keys, chronicles, stint, nimcrypto, + tables, hashes, times, algorithm, sets, sequtils, bearssl, random, + chronos, eth/keys, chronicles, stint, nimcrypto/keccak, enode export sets # TODO: This should not be needed, but compilation fails otherwise @@ -26,6 +26,7 @@ type pongFutures: Table[seq[byte], Future[bool]] pingFutures: Table[Node, Future[bool]] neighboursCallbacks: Table[Node, proc(n: seq[Node]) {.gcsafe.}] + rng: ref BrHmacDrbgContext NodeId* = UInt256 @@ -231,12 +232,15 @@ proc neighbours(r: RoutingTable, id: NodeId, k: int = BUCKET_SIZE): seq[Node] = proc len(r: RoutingTable): int = for b in r.buckets: result += b.len -proc newKademliaProtocol*[Wire](thisNode: Node, - wire: Wire): KademliaProtocol[Wire] = +proc newKademliaProtocol*[Wire]( + thisNode: Node, wire: Wire, rng = newRng()): KademliaProtocol[Wire] = + if rng == nil: raiseAssert "Need an RNG" # doAssert gives compile error on mac + result.new() result.thisNode = thisNode result.wire = wire result.routing.init(thisNode) + result.rng = rng proc bond(k: KademliaProtocol, n: Node): Future[bool] {.async, gcsafe.} @@ -408,7 +412,10 @@ proc lookup*(k: KademliaProtocol, nodeId: NodeId): Future[seq[Node]] {.async.} = proc lookupRandom*(k: KademliaProtocol): Future[seq[Node]] = var id: NodeId - discard randomBytes(addr id, id.sizeof) + var buf: array[sizeof(id), byte] + brHmacDrbgGenerate(k.rng[], buf) + copyMem(addr id, addr buf[0], sizeof(id)) + k.lookup(id) proc resolve*(k: KademliaProtocol, id: NodeId): Future[Node] {.async.} = diff --git a/eth/p2p/private/p2p_types.nim b/eth/p2p/private/p2p_types.nim index 86614cf..b0193c1 100644 --- a/eth/p2p/private/p2p_types.nim +++ b/eth/p2p/private/p2p_types.nim @@ -1,5 +1,5 @@ import - deques, tables, + deques, tables, bearssl, eth/[rlp, keys], chronos, eth/common/eth_types, ../enode, ../kademlia, ../discovery, ../rlpxcrypt @@ -24,6 +24,7 @@ type discovery*: DiscoveryProtocol when useSnappy: protocolVersion*: uint + rng*: ref BrHmacDrbgContext Peer* = ref object remote*: Node diff --git a/eth/p2p/rlpx.nim b/eth/p2p/rlpx.nim index 82d7b08..2de0e9c 100644 --- a/eth/p2p/rlpx.nim +++ b/eth/p2p/rlpx.nim @@ -461,7 +461,7 @@ proc waitSingleMsg(peer: Peer, MsgType: type): Future[MsgType] {.async.} = result = checkedRlpRead(peer, nextMsgData, MsgType) logReceivedMsg(peer, result) return - except RlpError: + except rlp.RlpError: await peer.disconnectAndRaise(BreachOfProtocol, "Invalid RLPx message body") @@ -969,11 +969,12 @@ proc rlpxConnect*(node: EthereumNode, remote: Node): Future[Peer] {.async.} = try: result.transport = await connect(ta) var handshake = Handshake.tryInit( - node.keys, {Initiator, EIP8}, node.baseProtocolVersion).tryGet() + node.rng[], node.keys, {Initiator, EIP8}, node.baseProtocolVersion).tryGet() var authMsg: array[AuthMessageMaxEIP8, byte] var authMsgLen = 0 - authMessage(handshake, remote.node.pubkey, authMsg, authMsgLen).tryGet() + authMessage( + handshake, node.rng[], remote.node.pubkey, authMsg, authMsgLen).tryGet() var res = await result.transport.write(addr authMsg[0], authMsgLen) if res != authMsgLen: raisePeerDisconnected("Unexpected disconnect while authenticating", @@ -1055,7 +1056,8 @@ proc rlpxAccept*(node: EthereumNode, result.transport = transport result.network = node - var handshake = HandShake.tryInit(node.keys, {auth.Responder}).tryGet + var handshake = + HandShake.tryInit(node.rng[], node.keys, {auth.Responder}).tryGet var ok = false try: @@ -1078,7 +1080,7 @@ proc rlpxAccept*(node: EthereumNode, var ackMsg: array[AckMessageMaxEIP8, byte] var ackMsgLen: int - handshake.ackMessage(ackMsg, ackMsgLen).tryGet() + handshake.ackMessage(node.rng[], ackMsg, ackMsgLen).tryGet() var res = await transport.write(addr ackMsg[0], ackMsgLen) if res != ackMsgLen: raisePeerDisconnected("Unexpected disconnect while authenticating", diff --git a/eth/p2p/rlpx.nim.generated.nim b/eth/p2p/rlpx.nim.generated.nim deleted file mode 100644 index 6ffa31d..0000000 --- a/eth/p2p/rlpx.nim.generated.nim +++ /dev/null @@ -1,196 +0,0 @@ - -## Generated at line 781 -type - DevP2P* = object -type - helloObj* = object - version*: uint - clientId*: string - capabilities*: seq[Capability] - listenPort*: uint - nodeId*: array[RawPublicKeySize, byte] - -template hello*(PROTO: type DevP2P): type = - helloObj - -template msgProtocol*(MSG: type helloObj): type = - DevP2P - -template RecType*(MSG: type helloObj): untyped = - helloObj - -template msgId*(MSG: type helloObj): int = - 0 - -type - sendDisconnectMsgObj* = object - reason*: DisconnectionReasonList - -template sendDisconnectMsg*(PROTO: type DevP2P): type = - sendDisconnectMsgObj - -template msgProtocol*(MSG: type sendDisconnectMsgObj): type = - DevP2P - -template RecType*(MSG: type sendDisconnectMsgObj): untyped = - sendDisconnectMsgObj - -template msgId*(MSG: type sendDisconnectMsgObj): int = - 1 - -type - pingObj* = object - emptyList*: EmptyList - -template ping*(PROTO: type DevP2P): type = - pingObj - -template msgProtocol*(MSG: type pingObj): type = - DevP2P - -template RecType*(MSG: type pingObj): untyped = - pingObj - -template msgId*(MSG: type pingObj): int = - 2 - -type - pongObj* = object - emptyList*: EmptyList - -template pong*(PROTO: type DevP2P): type = - pongObj - -template msgProtocol*(MSG: type pongObj): type = - DevP2P - -template RecType*(MSG: type pongObj): untyped = - pongObj - -template msgId*(MSG: type pongObj): int = - 3 - -var DevP2PProtocolObj = initProtocol("p2p", 5, nil, nil) -var DevP2PProtocol = addr DevP2PProtocolObj -template protocolInfo*(P`gensym75730262: type DevP2P): auto = - DevP2PProtocol - -proc hello*(peerOrResponder: Peer; version: uint; clientId: string; - capabilities: seq[Capability]; listenPort: uint; - nodeId: array[RawPublicKeySize, byte]): Future[void] {.gcsafe.} = - let peer = getPeer(peerOrResponder) - var writer = initRlpWriter() - const - perProtocolMsgId = 0 - let perPeerMsgId = 0 - append(writer, perPeerMsgId) - startList(writer, 5) - append(writer, version) - append(writer, clientId) - append(writer, capabilities) - append(writer, listenPort) - append(writer, nodeId) - let msgBytes = finish(writer) - return sendMsg(peer, msgBytes) - -proc sendDisconnectMsg*(peerOrResponder: Peer; reason: DisconnectionReasonList): Future[ - void] {.gcsafe.} = - let peer = getPeer(peerOrResponder) - var writer = initRlpWriter() - const - perProtocolMsgId = 1 - let perPeerMsgId = 1 - append(writer, perPeerMsgId) - append(writer, reason) - let msgBytes = finish(writer) - return sendMsg(peer, msgBytes) - -proc ping*(peerOrResponder: Peer; emptyList: EmptyList): Future[void] {.gcsafe.} = - let peer = getPeer(peerOrResponder) - var writer = initRlpWriter() - const - perProtocolMsgId = 2 - let perPeerMsgId = 2 - append(writer, perPeerMsgId) - append(writer, emptyList) - let msgBytes = finish(writer) - return sendMsg(peer, msgBytes) - -proc pong*(peerOrResponder: Peer; emptyList: EmptyList): Future[void] {.gcsafe.} = - let peer = getPeer(peerOrResponder) - var writer = initRlpWriter() - const - perProtocolMsgId = 3 - let perPeerMsgId = 3 - append(writer, perPeerMsgId) - append(writer, emptyList) - let msgBytes = finish(writer) - return sendMsg(peer, msgBytes) - -proc sendDisconnectMsgUserHandler(peer: Peer; reason: DisconnectionReasonList) {. - gcsafe, async.} = - type - CurrentProtocol = DevP2P - const - perProtocolMsgId = 1 - trace "disconnect message received", reason = reason.value, peer - await peer.disconnect(reason.value, false) - -proc pingUserHandler(peer: Peer; emptyList: EmptyList) {.gcsafe, async.} = - type - CurrentProtocol = DevP2P - const - perProtocolMsgId = 2 - discard peer.pong(EmptyList()) - -proc pongUserHandler(peer: Peer; emptyList: EmptyList) {.gcsafe, async.} = - type - CurrentProtocol = DevP2P - const - perProtocolMsgId = 3 - discard - -proc helloThunk(peer: Peer; _`gensym75730215: int; data`gensym75730216: Rlp) {.async, - gcsafe.} = - var rlp = data`gensym75730216 - var msg {.noinit.}: helloObj - tryEnterList(rlp) - msg.version = checkedRlpRead(peer, rlp, uint) - msg.clientId = checkedRlpRead(peer, rlp, string) - msg.capabilities = checkedRlpRead(peer, rlp, seq[Capability]) - msg.listenPort = checkedRlpRead(peer, rlp, uint) - msg.nodeId = checkedRlpRead(peer, rlp, array[RawPublicKeySize, byte]) - -proc sendDisconnectMsgThunk(peer: Peer; _`gensym75730250: int; - data`gensym75730251: Rlp) {.async, gcsafe.} = - var rlp = data`gensym75730251 - var msg {.noinit.}: sendDisconnectMsgObj - msg.reason = checkedRlpRead(peer, rlp, DisconnectionReasonList) - await(sendDisconnectMsgUserHandler(peer, msg.reason)) - -proc pingThunk(peer: Peer; _`gensym75730252: int; data`gensym75730253: Rlp) {.async, - gcsafe.} = - var rlp = data`gensym75730253 - var msg {.noinit.}: pingObj - msg.emptyList = checkedRlpRead(peer, rlp, EmptyList) - await(pingUserHandler(peer, msg.emptyList)) - -proc pongThunk(peer: Peer; _`gensym75730254: int; data`gensym75730255: Rlp) {.async, - gcsafe.} = - var rlp = data`gensym75730255 - var msg {.noinit.}: pongObj - msg.emptyList = checkedRlpRead(peer, rlp, EmptyList) - await(pongUserHandler(peer, msg.emptyList)) - -registerMsg(DevP2PProtocol, 0, "hello", helloThunk, messagePrinter[helloObj], - requestResolver[helloObj], nextMsgResolver[helloObj]) -registerMsg(DevP2PProtocol, 1, "sendDisconnectMsg", sendDisconnectMsgThunk, - messagePrinter[sendDisconnectMsgObj], - requestResolver[sendDisconnectMsgObj], - nextMsgResolver[sendDisconnectMsgObj]) -registerMsg(DevP2PProtocol, 2, "ping", pingThunk, messagePrinter[pingObj], - requestResolver[pingObj], nextMsgResolver[pingObj]) -registerMsg(DevP2PProtocol, 3, "pong", pongThunk, messagePrinter[pongObj], - requestResolver[pongObj], nextMsgResolver[pongObj]) -setEventHandlers(DevP2PProtocol, nil, nil) -registerProtocol(DevP2PProtocol) \ No newline at end of file diff --git a/eth/p2p/rlpx_protocols/whisper/whisper_types.nim b/eth/p2p/rlpx_protocols/whisper/whisper_types.nim index 6bb068b..f8f3bce 100644 --- a/eth/p2p/rlpx_protocols/whisper/whisper_types.nim +++ b/eth/p2p/rlpx_protocols/whisper/whisper_types.nim @@ -9,9 +9,9 @@ # import - algorithm, bitops, math, options, tables, times, chronicles, hashes, strutils, - stew/[byteutils, endians2], metrics, - nimcrypto/[bcmode, hash, keccak, rijndael, sysrand], + algorithm, bitops, math, options, tables, times, chronicles, hashes, + stew/[byteutils, endians2], metrics, bearssl, + nimcrypto/[bcmode, hash, keccak, rijndael], eth/[keys, rlp, p2p], eth/p2p/ecies logScope: @@ -158,12 +158,10 @@ proc topicBloom*(topic: Topic): Bloom = doAssert idx <= 511 result[idx div 8] = result[idx div 8] or byte(1 shl (idx and 7'u16)) -proc generateRandomID*(): string = +proc generateRandomID*(rng: var BrHmacDrbgContext): string = var bytes: array[256 div 8, byte] - while true: # XXX: error instead of looping? - if randomBytes(bytes) == 256 div 8: - result = toHex(bytes) - break + brHmacDrbgGenerate(rng, bytes) + toHex(bytes) proc `or`(a, b: Bloom): Bloom = for i in 0.. 0: - if m.bloom.len != bloomSize: - raise newException(UselessPeerError, "Bloomfilter size mismatch") - else: - whisperPeer.bloom.bytesCopy(m.bloom) - else: - whisperPeer.bloom = fullBloom() - whisperPeer.isLightNode = m.isLightNode - if whisperPeer.isLightNode and whisperNet.config.isLightNode: - raise newException(UselessPeerError, "Two light nodes connected") - whisperPeer.received.init() - whisperPeer.trusted = false - whisperPeer.initialized = true - if not whisperNet.config.isLightNode: - traceAsyncErrors peer.run() - debug "Whisper peer initialized", peer - -setEventHandlers(WhisperProtocol, WhisperPeerConnected, nil) -registerProtocol(WhisperProtocol) \ No newline at end of file diff --git a/tests/fuzzing/rlpx/thunk.nim b/tests/fuzzing/rlpx/thunk.nim index 27bc9e1..d418ce4 100644 --- a/tests/fuzzing/rlpx/thunk.nim +++ b/tests/fuzzing/rlpx/thunk.nim @@ -9,12 +9,13 @@ var node2: EthereumNode peer: Peer +let rng = newRng() # This is not a good example of a fuzzing test and it would be much better # to mock more to get rid of anything sockets, async, etc. # However, it can and has provided reasonably quick results anyhow. init: - node1 = setupTestNode(eth, Whisper) - node2 = setupTestNode(eth, Whisper) + node1 = setupTestNode(rng, eth, Whisper) + node2 = setupTestNode(rng, eth, Whisper) node2.startListening() peer = waitFor node1.rlpxConnect(newNode(node2.toENode())) diff --git a/tests/keyfile/test_keyfile.nim b/tests/keyfile/test_keyfile.nim index 4d9b9c8..9d0fd4c 100644 --- a/tests/keyfile/test_keyfile.nim +++ b/tests/keyfile/test_keyfile.nim @@ -14,6 +14,8 @@ import eth/keys, eth/keyfile/[keyfile], json, os, unittest # Test vectors copied from # https://github.com/ethereum/tests/blob/develop/KeyStoreTests/basic_tests.json +let rng = newRng() + var TestVectors = [ %*{ "keyfile": { @@ -114,7 +116,7 @@ suite "KeyFile test suite": check: seckey.error == KeyFileError.IncorrectMac test "Create/Save/Load test": - var seckey0 = PrivateKey.random()[] + var seckey0 = PrivateKey.random(rng[]) let jobject = createKeyFileJson(seckey0, "randompassword")[] check: diff --git a/tests/keys/test_keys.nim b/tests/keys/test_keys.nim index d4cfa67..f9f1e8e 100644 --- a/tests/keys/test_keys.nim +++ b/tests/keys/test_keys.nim @@ -10,7 +10,7 @@ {.used.} import unittest -import eth/keys +import eth/keys, bearssl import nimcrypto/hash, nimcrypto/keccak, nimcrypto/utils from strutils import toLowerAscii @@ -25,6 +25,7 @@ proc compare(x: openarray[byte], y: openarray[byte]): bool = break let message = "message".toBytes() +let rng = newRng() const pkbytes = "58d23b55bc9cdce1f18c2500f40ff4ab7245df9a89505e9b1fa4851f623d241d" @@ -80,7 +81,7 @@ suite "ECC/ECDSA/ECDHE tests suite": var s = PrivateKey.fromHex(pkbytes)[] var mhash = keccak256.digest(message) var signature = s.sign(message) - var p = recover(signature, mhash)[] + var p = recover(signature, SkMessage(mhash.data))[] check: s.toPublicKey() == p @@ -130,7 +131,7 @@ suite "ECC/ECDSA/ECDHE tests suite": test "EIP-55 100 addresses": for i in 1..100: - var kp = KeyPair.random()[] + var kp = KeyPair.random(rng[]) var chaddress = kp.pubkey.toChecksumAddress() var noaddress = kp.pubkey.toAddress() if noaddress != chaddress: @@ -206,9 +207,9 @@ suite "ECC/ECDSA/ECDHE tests suite": var s = PrivateKey.fromRaw(keccak256.digest("sec").data)[] var m = keccak256.digest("msg") - var sig = sign(s, m) + var sig = sign(s, SkMessage(m.data)) var sersig = sig.toRaw() - var key = recover(sig, m)[] + var key = recover(sig, SkMessage(m.data))[] var serkey = key.toRaw() check: compare(sersig, check1) == true @@ -217,18 +218,19 @@ suite "ECC/ECDSA/ECDHE tests suite": test "ECDSA/100 signatures": # signature test for i in 1..100: - var m = PrivateKey.random()[].toRaw - var s = PrivateKey.random()[] + var m: array[32, byte] + brHmacDrbgGenerate(rng[], m) + var s = PrivateKey.random(rng[]) var key = s.toPublicKey() - let sig = sign(s, m) - let rkey = recover(sig, m)[] + let sig = sign(s, SkMessage(m)) + let rkey = recover(sig, SkMessage(m))[] check: key == rkey test "KEYS/100 create/recovery keys": # key create/recovery test for i in 1..100: - var s = PrivateKey.random()[] + var s = PrivateKey.random(rng[]) var key = s.toPublicKey() let rkey = PublicKey.fromRaw(key.toRaw())[] check: @@ -237,9 +239,9 @@ suite "ECC/ECDSA/ECDHE tests suite": test "ECDHE/100 shared secrets": # ECDHE shared secret test for i in 1..100: - var aliceSecret = PrivateKey.random()[] + var aliceSecret = PrivateKey.random(rng[]) var alicePublic = aliceSecret.toPublicKey() - var bobSecret = PrivateKey.random()[] + var bobSecret = PrivateKey.random(rng[]) var bobPublic = bobSecret.toPublicKey() var secret1 = ecdhRaw(aliceSecret, bobPublic) var secret2 = ecdhRaw(bobSecret, alicePublic) diff --git a/tests/p2p/discv5_test_helper.nim b/tests/p2p/discv5_test_helper.nim index ab0a898..299eea4 100644 --- a/tests/p2p/discv5_test_helper.nim +++ b/tests/p2p/discv5_test_helper.nim @@ -1,14 +1,13 @@ import - testutils/unittests, stew/shims/net, nimcrypto, + testutils/unittests, stew/shims/net, bearssl, eth/[keys, rlp, trie/db], eth/p2p/discoveryv5/[discovery_db, enr, node, types, routing_table, encoding], eth/p2p/discoveryv5/protocol as discv5_protocol - proc localAddress*(port: int): Address = Address(ip: ValidIpAddress.init("127.0.0.1"), port: Port(port)) -proc initDiscoveryNode*(privKey: PrivateKey, address: Address, +proc initDiscoveryNode*(rng: ref BrHmacDrbgContext, privKey: PrivateKey, address: Address, bootstrapRecords: openarray[Record] = [], localEnrFields: openarray[FieldPair] = []): discv5_protocol.Protocol = @@ -17,7 +16,7 @@ proc initDiscoveryNode*(privKey: PrivateKey, address: Address, some(address.ip), address.port, address.port, bootstrapRecords = bootstrapRecords, - localEnrFields = localEnrFields) + localEnrFields = localEnrFields, rng = rng) result.open() @@ -26,33 +25,34 @@ proc nodeIdInNodes*(id: NodeId, nodes: openarray[Node]): bool = if id == n.id: return true # Creating a random packet with specific nodeid each time -proc randomPacket*(tag: PacketTag): seq[byte] = +proc randomPacket*(rng: var BrHmacDrbgContext, tag: PacketTag): seq[byte] = var authTag: AuthTag msg: array[44, byte] - check randomBytes(authTag) == authTag.len - check randomBytes(msg) == msg.len + brHmacDrbgGenerate(rng, authTag) + brHmacDrbgGenerate(rng, msg) result.add(tag) result.add(rlp.encode(authTag)) result.add(msg) -proc generateNode*(privKey = PrivateKey.random()[], port: int = 20302, +proc generateNode*(privKey: PrivateKey, port: int = 20302, localEnrFields: openarray[FieldPair] = []): Node = let port = Port(port) let enr = enr.Record.init(1, privKey, some(ValidIpAddress.init("127.0.0.1")), port, port, localEnrFields).expect("Properly intialized private key") result = newNode(enr).expect("Properly initialized node") -proc nodeAtDistance*(n: Node, d: uint32): Node = +proc nodeAtDistance*(n: Node, rng: var BrHmacDrbgContext, d: uint32): Node = while true: - let node = generateNode() + let node = generateNode(PrivateKey.random(rng)) if logDist(n.id, node.id) == d: return node -proc nodesAtDistance*(n: Node, d: uint32, amount: int): seq[Node] = +proc nodesAtDistance*( + n: Node, rng: var BrHmacDrbgContext, d: uint32, amount: int): seq[Node] = for i in 0.. Split only the branch in range of own id @@ -13,11 +16,11 @@ suite "Routing Table Tests": for j in 0..5'u32: for i in 0.. Split only the branch in range of own id @@ -25,19 +28,19 @@ suite "Routing Table Tests": # Add 16 nodes, distance 256 for i in 0.. Split only the branch in range of own id table.init(node, 1) # create a full bucket - let bucketNodes = node.nodesAtDistance(256, BUCKET_SIZE) + let bucketNodes = node.nodesAtDistance(rng[], 256, BUCKET_SIZE) for n in bucketNodes: check table.addNode(n) == nil # create a full replacement cache - let replacementNodes = node.nodesAtDistance(256, REPLACEMENT_CACHE_SIZE) + let replacementNodes = node.nodesAtDistance(rng[], 256, REPLACEMENT_CACHE_SIZE) for n in replacementNodes: check table.addNode(n) != nil # Add one more node to replacement (would drop first one) - let lastNode = node.nodeAtDistance(256) + let lastNode = node.nodeAtDistance(rng[], 256) check table.addNode(lastNode) != nil # This should replace the last node in the bucket, with the last one of @@ -101,7 +104,7 @@ suite "Routing Table Tests": check (table.getNode(bucketNodes[bucketNodes.high].id)).isNone() test "Empty bucket": - let node = generateNode() + let node = generateNode(PrivateKey.random(rng[])) var table: RoutingTable # bitsPerHop = 1 -> Split only the branch in range of own id @@ -110,29 +113,29 @@ suite "Routing Table Tests": check table.nodeToRevalidate().isNil() # try to replace not existing node - table.replaceNode(generateNode()) + table.replaceNode(generateNode(PrivateKey.random(rng[]))) check table.len == 0 - let addedNode = generateNode() + let addedNode = generateNode(PrivateKey.random(rng[])) check table.addNode(addedNode) == nil check table.len == 1 # try to replace not existing node - table.replaceNode(generateNode()) + table.replaceNode(generateNode(PrivateKey.random(rng[]))) check table.len == 1 table.replaceNode(addedNode) check table.len == 0 test "Empty replacement cache": - let node = generateNode() + let node = generateNode(PrivateKey.random(rng[])) var table: RoutingTable # bitsPerHop = 1 -> Split only the branch in range of own id table.init(node, 1) # create a full bucket TODO: no need to store bucketNodes - let bucketNodes = node.nodesAtDistance(256, BUCKET_SIZE) + let bucketNodes = node.nodesAtDistance(rng[], 256, BUCKET_SIZE) for n in bucketNodes: check table.addNode(n) == nil @@ -141,21 +144,21 @@ suite "Routing Table Tests": check (table.getNode(bucketNodes[bucketNodes.high].id)).isNone() test "Double add": - let node = generateNode() + let node = generateNode(PrivateKey.random(rng[])) var table: RoutingTable # bitsPerHop = 1 -> Split only the branch in range of own id table.init(node, 1) - let doubleNode = node.nodeAtDistance(256) + let doubleNode = node.nodeAtDistance(rng[], 256) # Try to add the node twice check table.addNode(doubleNode) == nil check table.addNode(doubleNode) == nil for n in 0.. Split only the branch in range of own id table.init(node, 1) # create a full bucket - let bucketNodes = node.nodesAtDistance(256, BUCKET_SIZE) + let bucketNodes = node.nodesAtDistance(rng[], 256, BUCKET_SIZE) for n in bucketNodes: check table.addNode(n) == nil # create a full replacement cache - let replacementNodes = node.nodesAtDistance(256, REPLACEMENT_CACHE_SIZE) + let replacementNodes = node.nodesAtDistance(rng[], 256, REPLACEMENT_CACHE_SIZE) for n in replacementNodes: check table.addNode(n) != nil @@ -201,14 +204,14 @@ suite "Routing Table Tests": check (table.getNode(bucketNodes[bucketNodes.high].id)).isNone() test "Just seen": - let node = generateNode() + let node = generateNode(PrivateKey.random(rng[])) var table: RoutingTable # bitsPerHop = 1 -> Split only the branch in range of own id table.init(node, 1) # create a full bucket - let bucketNodes = node.nodesAtDistance(256, BUCKET_SIZE) + let bucketNodes = node.nodesAtDistance(rng[], 256, BUCKET_SIZE) for n in bucketNodes: check table.addNode(n) == nil @@ -221,19 +224,19 @@ suite "Routing Table Tests": check (table.getNode(n.id)).isNone() test "Just seen replacement": - let node = generateNode() + let node = generateNode(PrivateKey.random(rng[])) var table: RoutingTable # bitsPerHop = 1 -> Split only the branch in range of own id table.init(node, 1) # create a full bucket - let bucketNodes = node.nodesAtDistance(256, BUCKET_SIZE) + let bucketNodes = node.nodesAtDistance(rng[], 256, BUCKET_SIZE) for n in bucketNodes: check table.addNode(n) == nil # create a full replacement cache - let replacementNodes = node.nodesAtDistance(256, REPLACEMENT_CACHE_SIZE) + let replacementNodes = node.nodesAtDistance(rng[], 256, REPLACEMENT_CACHE_SIZE) for n in replacementNodes: check table.addNode(n) != nil diff --git a/tests/p2p/test_shh.nim b/tests/p2p/test_shh.nim index decb24c..31f6d4e 100644 --- a/tests/p2p/test_shh.nim +++ b/tests/p2p/test_shh.nim @@ -11,10 +11,12 @@ import sequtils, options, unittest, tables, nimcrypto/hash, eth/[keys, rlp], eth/p2p/rlpx_protocols/whisper/whisper_types as whisper +let rng = newRng() + suite "Whisper payload": test "should roundtrip without keys": let payload = Payload(payload: @[byte 0, 1, 2]) - let encoded = whisper.encode(payload) + let encoded = whisper.encode(rng[], payload) let decoded = whisper.decode(encoded.get()) check: @@ -26,7 +28,7 @@ suite "Whisper payload": test "should roundtrip with symmetric encryption": var symKey: SymKey let payload = Payload(symKey: some(symKey), payload: @[byte 0, 1, 2]) - let encoded = whisper.encode(payload) + let encoded = whisper.encode(rng[], payload) let decoded = whisper.decode(encoded.get(), symKey = some(symKey)) check: @@ -36,10 +38,10 @@ suite "Whisper payload": decoded.get().padding.get().len == 251 # 256 -1 -1 -3 test "should roundtrip with signature": - let privKey = PrivateKey.random()[] + let privKey = PrivateKey.random(rng[]) let payload = Payload(src: some(privKey), payload: @[byte 0, 1, 2]) - let encoded = whisper.encode(payload) + let encoded = whisper.encode(rng[], payload) let decoded = whisper.decode(encoded.get()) check: @@ -49,11 +51,11 @@ suite "Whisper payload": decoded.get().padding.get().len == 186 # 256 -1 -1 -3 -65 test "should roundtrip with asymmetric encryption": - let privKey = PrivateKey.random()[] + let privKey = PrivateKey.random(rng[]) let payload = Payload(dst: some(privKey.toPublicKey()), payload: @[byte 0, 1, 2]) - let encoded = whisper.encode(payload) + let encoded = whisper.encode(rng[], payload) let decoded = whisper.decode(encoded.get(), dst = some(privKey)) check: @@ -74,7 +76,7 @@ suite "Whisper payload": suite "Whisper payload padding": test "should do max padding": let payload = Payload(payload: repeat(byte 1, 254)) - let encoded = whisper.encode(payload) + let encoded = whisper.encode(rng[], payload) let decoded = whisper.decode(encoded.get()) check: @@ -84,10 +86,10 @@ suite "Whisper payload padding": decoded.get().padding.get().len == 256 # as dataLen == 256 test "should do max padding with signature": - let privKey = PrivateKey.random()[] + let privKey = PrivateKey.random(rng[]) let payload = Payload(src: some(privKey), payload: repeat(byte 1, 189)) - let encoded = whisper.encode(payload) + let encoded = whisper.encode(rng[], payload) let decoded = whisper.decode(encoded.get()) check: @@ -99,7 +101,7 @@ suite "Whisper payload padding": test "should do min padding": let payload = Payload(payload: repeat(byte 1, 253)) - let encoded = whisper.encode(payload) + let encoded = whisper.encode(rng[], payload) let decoded = whisper.decode(encoded.get()) check: @@ -109,10 +111,10 @@ suite "Whisper payload padding": decoded.get().padding.get().len == 1 # as dataLen == 255 test "should do min padding with signature": - let privKey = PrivateKey.random()[] + let privKey = PrivateKey.random(rng[]) let payload = Payload(src: some(privKey), payload: repeat(byte 1, 188)) - let encoded = whisper.encode(payload) + let encoded = whisper.encode(rng[], payload) let decoded = whisper.decode(encoded.get()) check: @@ -125,7 +127,7 @@ suite "Whisper payload padding": test "should roundtrip custom padding": let payload = Payload(payload: repeat(byte 1, 10), padding: some(repeat(byte 2, 100))) - let encoded = whisper.encode(payload) + let encoded = whisper.encode(rng[], payload) let decoded = whisper.decode(encoded.get()) check: @@ -138,7 +140,7 @@ suite "Whisper payload padding": let padding: seq[byte] = @[] let payload = Payload(payload: repeat(byte 1, 10), padding: some(padding)) - let encoded = whisper.encode(payload) + let encoded = whisper.encode(rng[], payload) let decoded = whisper.decode(encoded.get()) check: @@ -147,10 +149,10 @@ suite "Whisper payload padding": decoded.get().padding.isNone() test "should roundtrip custom padding with signature": - let privKey = PrivateKey.random()[] + let privKey = PrivateKey.random(rng[]) let payload = Payload(src: some(privKey), payload: repeat(byte 1, 10), padding: some(repeat(byte 2, 100))) - let encoded = whisper.encode(payload) + let encoded = whisper.encode(rng[], payload) let decoded = whisper.decode(encoded.get()) check: @@ -162,10 +164,10 @@ suite "Whisper payload padding": test "should roundtrip custom 0 padding with signature": let padding: seq[byte] = @[] - let privKey = PrivateKey.random()[] + let privKey = PrivateKey.random(rng[]) let payload = Payload(src: some(privKey), payload: repeat(byte 1, 10), padding: some(padding)) - let encoded = whisper.encode(payload) + let encoded = whisper.encode(rng[], payload) let decoded = whisper.decode(encoded.get()) check: @@ -276,7 +278,7 @@ proc prepFilterTestMsg(pubKey = none[PublicKey](), symKey = none[SymKey](), padding = none[seq[byte]]()): Message = let payload = Payload(dst: pubKey, symKey: symKey, src: src, payload: @[byte 0, 1, 2], padding: padding) - let encoded = whisper.encode(payload) + let encoded = whisper.encode(rng[], payload) let env = Envelope(expiry: 1, ttl: 1, topic: topic, data: encoded.get(), nonce: 0) result = initMessage(env) @@ -289,7 +291,7 @@ suite "Whisper filter": var filters = initTable[string, Filter]() let filter = initFilter(symKey = some(symKey), topics = @[topic]) - let filterId = filters.subscribeFilter(filter) + let filterId = subscribeFilter(rng[], filters, filter) notify(filters, msg) @@ -300,14 +302,14 @@ suite "Whisper filter": messages[0].dst.isNone() test "should notify filter on message with asymmetric encryption": - let privKey = PrivateKey.random()[] + let privKey = PrivateKey.random(rng[]) let topic = [byte 0, 0, 0, 0] let msg = prepFilterTestMsg(pubKey = some(privKey.toPublicKey()), topic = topic) var filters = initTable[string, Filter]() let filter = initFilter(privateKey = some(privKey), topics = @[topic]) - let filterId = filters.subscribeFilter(filter) + let filterId = subscribeFilter(rng[], filters, filter) notify(filters, msg) @@ -318,14 +320,14 @@ suite "Whisper filter": messages[0].dst.isSome() test "should notify filter on message with signature": - let privKey = PrivateKey.random()[] + let privKey = PrivateKey.random(rng[]) let topic = [byte 0, 0, 0, 0] let msg = prepFilterTestMsg(src = some(privKey), topic = topic) var filters = initTable[string, Filter]() let filter = initFilter(src = some(privKey.toPublicKey()), topics = @[topic]) - let filterId = filters.subscribeFilter(filter) + let filterId = subscribeFilter(rng[], filters, filter) notify(filters, msg) @@ -346,9 +348,9 @@ suite "Whisper filter": var filters = initTable[string, Filter]() let - filterId1 = filters.subscribeFilter( + filterId1 = subscribeFilter(rng[], filters, initFilter(topics = @[topic], powReq = 0.014492753623188406)) - filterId2 = filters.subscribeFilter( + filterId2 = subscribeFilter(rng[], filters, initFilter(topics = @[topic], powReq = 0.014492753623188407)) notify(filters, msg) @@ -366,8 +368,8 @@ suite "Whisper filter": var filters = initTable[string, Filter]() let - filterId1 = filters.subscribeFilter(initFilter(topics = @[topic1])) - filterId2 = filters.subscribeFilter(initFilter(topics = @[topic2])) + filterId1 = subscribeFilter(rng[], filters, initFilter(topics = @[topic1])) + filterId2 = subscribeFilter(rng[], filters, initFilter(topics = @[topic2])) notify(filters, msg) diff --git a/tests/p2p/test_shh_connect.nim b/tests/p2p/test_shh_connect.nim index f6ce979..a3d5270 100644 --- a/tests/p2p/test_shh_connect.nim +++ b/tests/p2p/test_shh_connect.nim @@ -8,7 +8,7 @@ # MIT license (LICENSE-MIT) import - sequtils, options, tables, chronos, testutils/unittests, + sequtils, options, tables, chronos, testutils/unittests, bearssl, eth/[keys, p2p], eth/p2p/rlpx_protocols/whisper_protocol, eth/p2p/peer_pool, ./p2p_test_helper @@ -20,8 +20,9 @@ let safeTTL = 5'u32 let waitInterval = messageInterval + 150.milliseconds procSuite "Whisper connections": - var node1 = setupTestNode(Whisper) - var node2 = setupTestNode(Whisper) + let rng = newRng() + var node1 = setupTestNode(rng, Whisper) + var node2 = setupTestNode(rng, Whisper) node2.startListening() waitFor node1.peerPool.connectToNode(newNode(node2.toENode())) asyncTest "Two peers connected": @@ -29,8 +30,8 @@ procSuite "Whisper connections": node1.peerPool.connectedNodes.len() == 1 asyncTest "Filters with encryption and signing": - let encryptKeyPair = KeyPair.random()[] - let signKeyPair = KeyPair.random()[] + let encryptKeyPair = KeyPair.random(rng[]) + let signKeyPair = KeyPair.random(rng[]) var symKey: SymKey let topic = [byte 0x12, 0, 0, 0] var filters: seq[string] = @[] @@ -294,7 +295,7 @@ procSuite "Whisper connections": node1.unsubscribeFilter(filter) == true asyncTest "Light node posting": - var ln1 = setupTestNode(Whisper) + var ln1 = setupTestNode(rng, Whisper) ln1.setLightNode(true) await ln1.peerPool.connectToNode(newNode(node2.toENode())) @@ -313,8 +314,8 @@ procSuite "Whisper connections": ln1.protocolState(Whisper).queue.items.len == 0 asyncTest "Connect two light nodes": - var ln1 = setupTestNode(Whisper) - var ln2 = setupTestNode(Whisper) + var ln1 = setupTestNode(rng, Whisper) + var ln2 = setupTestNode(rng, Whisper) ln1.setLightNode(true) ln2.setLightNode(true)