diff --git a/libp2p/crypto/crypto.nim b/libp2p/crypto/crypto.nim index a32ea9ab3..83401f4a0 100644 --- a/libp2p/crypto/crypto.nim +++ b/libp2p/crypto/crypto.nim @@ -8,6 +8,7 @@ ## those terms. ## This module implements Public Key and Private Key interface for libp2p. +import strutils import rsa, ecnist, ed25519/ed25519, secp import ../protobuf/minprotobuf, ../vbuffer import nimcrypto/[rijndael, blowfish, sha, sha2, hash, hmac, utils] @@ -572,6 +573,63 @@ proc makeSecret*(remoteEPublic: PublicKey, localEPrivate: PrivateKey, if localEPrivate.scheme == remoteEPublic.scheme: result = toSecret(remoteEPublic.eckey, localEPrivate.eckey, data) +proc getOrder*(remotePubkey, localNonce: openarray[byte], + localPubkey, remoteNonce: openarray[byte]): int = + ## Compare values and calculate `order` parameter. + var ctx: sha256 + ctx.init() + ctx.update(remotePubkey) + ctx.update(localNonce) + var digest1 = ctx.finish() + ctx.init() + ctx.update(localPubkey) + ctx.update(remoteNonce) + var digest2 = ctx.finish() + var diff = 0 + for i in 0 ..< len(digest1.data): + diff = int(digest1.data[i]) - int(digest2.data[i]) + result = (result and -not(diff)) or diff + +proc selectBest*(order: int, p1, p2: string): string = + ## Determines which algorithm to use from list `p1` and `p2`. + ## + ## Returns empty string if there no algorithms in common. + var f, s: seq[string] + if order < 0: + f = strutils.split(p2, ",") + s = strutils.split(p1, ",") + elif order > 0: + f = strutils.split(p1, ",") + s = strutils.split(p2, ",") + else: + var p = strutils.split(p1, ",") + result = p[0] + return + + for felement in f: + for selement in s: + if felement == selement: + result = felement + break + +proc createProposal*(nonce, pubkey: openarray[byte], + exchanges, ciphers, hashes: string): seq[byte] = + var msg = initProtoBuffer({WithUint32BeLength}) + msg.write(initProtoField(1, nonce)) + msg.write(initProtoField(2, pubkey)) + msg.write(initProtoField(3, exchanges)) + msg.write(initProtoField(4, ciphers)) + msg.write(initProtoField(5, hashes)) + msg.finish() + shallowCopy(result, msg.buffer) + +proc createExchange*(epubkey, signature: openarray[byte]): seq[byte] = + var msg = initProtoBuffer({WithUint32BeLength}) + msg.write(initProtoField(1, epubkey)) + msg.write(initProtoField(2, signature)) + msg.finish() + shallowCopy(result, msg.buffer) + ## Serialization/Deserialization helpers proc write*(vb: var VBuffer, pubkey: PublicKey) {.inline.} = diff --git a/libp2p/protobuf/minprotobuf.nim b/libp2p/protobuf/minprotobuf.nim index b36028eaa..c86b8244a 100644 --- a/libp2p/protobuf/minprotobuf.nim +++ b/libp2p/protobuf/minprotobuf.nim @@ -20,7 +20,7 @@ type ProtoFlags* = enum ## Protobuf's encoding types - WithVarintLength + WithVarintLength, WithUint32BeLength, WithUint32LeLength ProtoBuffer* = object ## Protobuf's message representation object @@ -128,6 +128,11 @@ proc initProtoBuffer*(options: set[ProtoFlags] = {}): ProtoBuffer = # in [0, 9]. result.buffer.setLen(10) result.offset = 10 + elif {WithUint32LeLength, WithUint32BeLength} * options != {}: + # Our buffer will start from position 4, so we can store length of buffer + # in [0, 9]. + result.buffer.setLen(4) + result.offset = 4 proc write*(pb: var ProtoBuffer, field: ProtoField) = ## Encode protobuf's field ``field`` and store it to protobuf's buffer ``pb``. @@ -184,6 +189,20 @@ proc finish*(pb: var ProtoBuffer) = let res = PB.putUVarint(pb.buffer.toOpenArray(pos, 9), usedBytes, size) doAssert(res == VarintStatus.Success) pb.offset = pos + elif WithUint32BeLength in pb.options: + let size = uint(len(pb.buffer) - 4) + pb.buffer[0] = byte(size shr 24) + pb.buffer[1] = byte(size shr 16) + pb.buffer[2] = byte(size shr 8) + pb.buffer[3] = byte(size) + pb.offset = 4 + elif WithUint32LeLength in pb.options: + let size = uint(len(pb.buffer) - 4) + pb.buffer[0] = byte(size) + pb.buffer[1] = byte(size shr 8) + pb.buffer[2] = byte(size shr 16) + pb.buffer[3] = byte(size shr 24) + pb.offset = 4 else: pb.offset = 0