diff --git a/examples/directchat.nim b/examples/directchat.nim index a0d7f9e43..8e5d06658 100644 --- a/examples/directchat.nim +++ b/examples/directchat.nim @@ -152,7 +152,7 @@ proc readInput(wfd: AsyncFD) {.thread.} = proc processInput(rfd: AsyncFD) {.async.} = let transp = fromPipe(rfd) - let seckey = PrivateKey.random(RSA) + let seckey = PrivateKey.random(RSA).get() let peerInfo = PeerInfo.init(seckey) var localAddress = DefaultAddr while true: diff --git a/libp2p/cid.nim b/libp2p/cid.nim index 2212bafea..c7b7bd014 100644 --- a/libp2p/cid.nim +++ b/libp2p/cid.nim @@ -95,7 +95,7 @@ proc decode(data: openarray[byte], cid: var Cid): CidStatus = if mcodec == InvalidMultiCodec: return CidStatus.Incorrect if not MultiHash.validate(vb.buffer.toOpenArray(vb.offset, - len(vb.buffer) - 1)): + vb.buffer.high)): return CidStatus.Incorrect vb.finish() cid.cidver = CIDv1 @@ -133,7 +133,7 @@ proc validate*(ctype: typedesc[Cid], data: openarray[byte]): bool = var res: VarintStatus if len(data) < 2: return false - let last = len(data) - 1 + let last = data.high if len(data) == 34: if data[0] == 0x12'u8 and data[1] == 0x20'u8: return true @@ -161,8 +161,8 @@ proc mhash*(cid: Cid): MultiHash = ## Returns MultiHash part of CID. if cid.cidver notin {CIDv0, CIDv1}: raise newException(CidError, "Incorrect CID!") - result = MultiHash.init(cid.data.buffer.toOpenArray(cid.hpos, - len(cid.data) - 1)) + result = MultiHash.init( + cid.data.buffer.toOpenArray(cid.hpos, cid.data.high)).tryGet() proc contentType*(cid: Cid): MultiCodec = ## Returns content type part of CID @@ -221,11 +221,11 @@ proc `==`*(a: Cid, b: Cid): bool = ## are equal, ``false`` otherwise. if a.mcodec == b.mcodec: var ah, bh: MultiHash - if MultiHash.decode(a.data.buffer.toOpenArray(a.hpos, - len(a.data) - 1), ah) == -1: + if MultiHash.decode( + a.data.buffer.toOpenArray(a.hpos, a.data.high), ah).isErr: return false - if MultiHash.decode(b.data.buffer.toOpenArray(b.hpos, - len(b.data) - 1), bh) == -1: + if MultiHash.decode( + b.data.buffer.toOpenArray(b.hpos, b.data.high), bh).isErr: return false result = (ah == bh) diff --git a/libp2p/crypto/crypto.nim b/libp2p/crypto/crypto.nim index ec5de7ffc..10a1d8edd 100644 --- a/libp2p/crypto/crypto.nim +++ b/libp2p/crypto/crypto.nim @@ -8,6 +8,9 @@ ## those terms. ## This module implements Public Key and Private Key interface for libp2p. + +{.push raises: [Defect].} + import rsa, ecnist, ed25519/ed25519, secp import ../protobuf/minprotobuf, ../vbuffer, ../multihash, ../multicodec import nimcrypto/[rijndael, blowfish, twofish, sha, sha2, hash, hmac, utils] @@ -79,172 +82,177 @@ type Signature* = object data*: seq[byte] - P2pKeyError* = object of CatchableError - P2pSigError* = object of CatchableError + CryptoError* = enum + KeyError, + SigError, + HashError, + SchemeError + + CryptoResult*[T] = Result[T, CryptoError] const SupportedSchemes* = {RSA, Ed25519, Secp256k1, ECDSA} SupportedSchemesInt* = {int8(RSA), int8(Ed25519), int8(Secp256k1), int8(ECDSA)} +template orError(exp: untyped, err: CryptoError): untyped = + (exp.mapErr do (_: auto) -> auto: err) + proc random*(t: typedesc[PrivateKey], scheme: PKScheme, - bits = DefaultKeySize): PrivateKey = + bits = DefaultKeySize): CryptoResult[PrivateKey] = ## Generate random private key for scheme ``scheme``. ## ## ``bits`` is number of bits for RSA key, ``bits`` value must be in ## [512, 4096], default value is 2048 bits. - doAssert(scheme in SupportedSchemes) - result = PrivateKey(scheme: scheme) - if scheme == RSA: - result.rsakey = RsaPrivateKey.random(bits) - elif scheme == Ed25519: - result.edkey = EdPrivateKey.random() - elif scheme == ECDSA: - result.eckey = EcPrivateKey.random(Secp256r1) - elif scheme == Secp256k1: - result.skkey = SkPrivateKey.random() + case scheme + of RSA: + let rsakey = ? RsaPrivateKey.random(bits).orError(KeyError) + ok(PrivateKey(scheme: scheme, rsakey: rsakey)) + of Ed25519: + let edkey = ? EdPrivateKey.random().orError(KeyError) + ok(PrivateKey(scheme: scheme, edkey: edkey)) + of ECDSA: + let eckey = ? EcPrivateKey.random(Secp256r1).orError(KeyError) + ok(PrivateKey(scheme: scheme, eckey: eckey)) + of Secp256k1: + let skkey = ? SkPrivateKey.random().orError(KeyError) + ok(PrivateKey(scheme: scheme, skkey: skkey)) + else: + err(SchemeError) proc random*(t: typedesc[KeyPair], scheme: PKScheme, - bits = DefaultKeySize): KeyPair = + bits = DefaultKeySize): CryptoResult[KeyPair] = ## Generate random key pair for scheme ``scheme``. ## ## ``bits`` is number of bits for RSA key, ``bits`` value must be in ## [512, 4096], default value is 2048 bits. - doAssert(scheme in SupportedSchemes) - result.seckey = PrivateKey(scheme: scheme) - result.pubkey = PublicKey(scheme: scheme) - if scheme == RSA: - var pair = RsaKeyPair.random(bits) - result.seckey.rsakey = pair.seckey - result.pubkey.rsakey = pair.pubkey - elif scheme == Ed25519: - var pair = EdKeyPair.random() - result.seckey.edkey = pair.seckey - result.pubkey.edkey = pair.pubkey - elif scheme == ECDSA: - var pair = EcKeyPair.random(Secp256r1) - result.seckey.eckey = pair.seckey - result.pubkey.eckey = pair.pubkey - elif scheme == Secp256k1: - var pair = SkKeyPair.random() - result.seckey.skkey = pair.seckey - result.pubkey.skkey = pair.pubkey + case scheme + of RSA: + let pair = ? RsaKeyPair.random(bits).orError(KeyError) + ok(KeyPair( + seckey: PrivateKey(scheme: scheme, rsakey: pair.seckey), + pubkey: PublicKey(scheme: scheme, rsakey: pair.pubkey))) + of Ed25519: + let pair = ? EdKeyPair.random().orError(KeyError) + ok(KeyPair( + seckey: PrivateKey(scheme: scheme, edkey: pair.seckey), + pubkey: PublicKey(scheme: scheme, edkey: pair.pubkey))) + of ECDSA: + let pair = ? EcKeyPair.random(Secp256r1).orError(KeyError) + ok(KeyPair( + seckey: PrivateKey(scheme: scheme, eckey: pair.seckey), + pubkey: PublicKey(scheme: scheme, eckey: pair.pubkey))) + of Secp256k1: + let pair = ? SkKeyPair.random().orError(KeyError) + ok(KeyPair( + seckey: PrivateKey(scheme: scheme, skkey: pair.seckey), + pubkey: PublicKey(scheme: scheme, skkey: pair.pubkey))) + else: + err(SchemeError) -proc getKey*(key: PrivateKey): PublicKey = +proc getKey*(key: PrivateKey): CryptoResult[PublicKey] = ## Get public key from corresponding private key ``key``. - result = PublicKey(scheme: key.scheme) - if key.scheme == RSA: - result.rsakey = key.rsakey.getKey() - elif key.scheme == Ed25519: - result.edkey = key.edkey.getKey() - elif key.scheme == ECDSA: - result.eckey = key.eckey.getKey() - elif key.scheme == Secp256k1: - result.skkey = key.skkey.getKey() + case key.scheme + of RSA: + let rsakey = key.rsakey.getKey() + ok(PublicKey(scheme: RSA, rsakey: rsakey)) + of Ed25519: + let edkey = key.edkey.getKey() + ok(PublicKey(scheme: Ed25519, edkey: edkey)) + of ECDSA: + let eckey = ? key.eckey.getKey().orError(KeyError) + ok(PublicKey(scheme: ECDSA, eckey: eckey)) + of Secp256k1: + let skkey = ? key.skkey.getKey().orError(KeyError) + ok(PublicKey(scheme: Secp256k1, skkey: skkey)) + else: + err(KeyError) -proc toRawBytes*(key: PrivateKey, data: var openarray[byte]): int = +proc toRawBytes*(key: PrivateKey | PublicKey, data: var openarray[byte]): CryptoResult[int] = ## Serialize private key ``key`` (using scheme's own serialization) and store ## it to ``data``. ## ## Returns number of bytes (octets) needed to store private key ``key``. - if key.scheme == RSA: - result = key.rsakey.toBytes(data) - elif key.scheme == Ed25519: - result = key.edkey.toBytes(data) - elif key.scheme == ECDSA: - result = key.eckey.toBytes(data) - elif key.scheme == Secp256k1: - result = key.skkey.toBytes(data) + case key.scheme + of RSA: + key.rsakey.toBytes(data).orError(KeyError) + of Ed25519: + ok(key.edkey.toBytes(data)) + of ECDSA: + key.eckey.toBytes(data).orError(KeyError) + of Secp256k1: + key.skkey.toBytes(data).orError(KeyError) + else: + err(KeyError) -proc toRawBytes*(key: PublicKey, data: var openarray[byte]): int = - ## Serialize public key ``key`` (using scheme's own serialization) and store - ## it to ``data``. - ## - ## Returns number of bytes (octets) needed to store public key ``key``. - if key.scheme == RSA: - result = key.rsakey.toBytes(data) - elif key.scheme == Ed25519: - result = key.edkey.toBytes(data) - elif key.scheme == ECDSA: - result = key.eckey.toBytes(data) - elif key.scheme == Secp256k1: - result = key.skkey.toBytes(data) - -proc getRawBytes*(key: PrivateKey): seq[byte] = +proc getRawBytes*(key: PrivateKey | PublicKey): CryptoResult[seq[byte]] = ## Return private key ``key`` in binary form (using scheme's own ## serialization). - if key.scheme == RSA: - result = key.rsakey.getBytes() - elif key.scheme == Ed25519: - result = key.edkey.getBytes() - elif key.scheme == ECDSA: - result = key.eckey.getBytes() - elif key.scheme == Secp256k1: - result = key.skkey.getBytes() + case key.scheme + of RSA: + key.rsakey.getBytes().orError(KeyError) + of Ed25519: + ok(key.edkey.getBytes()) + of ECDSA: + key.eckey.getBytes().orError(KeyError) + of Secp256k1: + ok(key.skkey.getBytes()) + else: + err(KeyError) -proc getRawBytes*(key: PublicKey): seq[byte] = - ## Return public key ``key`` in binary form (using scheme's own - ## serialization). - if key.scheme == RSA: - result = key.rsakey.getBytes() - elif key.scheme == Ed25519: - result = key.edkey.getBytes() - elif key.scheme == ECDSA: - result = key.eckey.getBytes() - elif key.scheme == Secp256k1: - result = key.skkey.getBytes() - -proc toBytes*(key: PrivateKey, data: var openarray[byte]): int = +proc toBytes*(key: PrivateKey, data: var openarray[byte]): CryptoResult[int] = ## Serialize private key ``key`` (using libp2p protobuf scheme) and store ## it to ``data``. ## ## Returns number of bytes (octets) needed to store private key ``key``. var msg = initProtoBuffer() msg.write(initProtoField(1, cast[uint64](key.scheme))) - msg.write(initProtoField(2, key.getRawBytes())) + msg.write(initProtoField(2, ? key.getRawBytes())) msg.finish() - result = len(msg.buffer) - if len(data) >= result: - copyMem(addr data[0], addr msg.buffer[0], len(msg.buffer)) + var blen = len(msg.buffer) + if len(data) >= blen: + copyMem(addr data[0], addr msg.buffer[0], blen) + ok(blen) -proc toBytes*(key: PublicKey, data: var openarray[byte]): int = +proc toBytes*(key: PublicKey, data: var openarray[byte]): CryptoResult[int] = ## Serialize public key ``key`` (using libp2p protobuf scheme) and store ## it to ``data``. ## ## Returns number of bytes (octets) needed to store public key ``key``. var msg = initProtoBuffer() msg.write(initProtoField(1, cast[uint64](key.scheme))) - msg.write(initProtoField(2, key.getRawBytes())) + msg.write(initProtoField(2, ? key.getRawBytes())) msg.finish() - result = len(msg.buffer) - if len(data) >= result: - copyMem(addr data[0], addr msg.buffer[0], len(msg.buffer)) + var blen = len(msg.buffer) + if len(data) >= blen and blen > 0: + copyMem(addr data[0], addr msg.buffer[0], blen) + ok(blen) proc toBytes*(sig: Signature, data: var openarray[byte]): int = ## Serialize signature ``sig`` and store it to ``data``. ## ## Returns number of bytes (octets) needed to store signature ``sig``. result = len(sig.data) - if len(data) >= result: + if len(data) >= result and result > 0: copyMem(addr data[0], unsafeAddr sig.data[0], len(sig.data)) -proc getBytes*(key: PrivateKey): seq[byte] = +proc getBytes*(key: PrivateKey): CryptoResult[seq[byte]] = ## Return private key ``key`` in binary form (using libp2p's protobuf ## serialization). var msg = initProtoBuffer() msg.write(initProtoField(1, cast[uint64](key.scheme))) - msg.write(initProtoField(2, key.getRawBytes())) + msg.write(initProtoField(2, ? key.getRawBytes())) msg.finish() - result = msg.buffer + ok(msg.buffer) -proc getBytes*(key: PublicKey): seq[byte] = +proc getBytes*(key: PublicKey): CryptoResult[seq[byte]] = ## Return public key ``key`` in binary form (using libp2p's protobuf ## serialization). var msg = initProtoBuffer() msg.write(initProtoField(1, cast[uint64](key.scheme))) - msg.write(initProtoField(2, key.getRawBytes())) + msg.write(initProtoField(2, ? key.getRawBytes())) msg.finish() - result = msg.buffer + ok(msg.buffer) proc getBytes*(sig: Signature): seq[byte] = ## Return signature ``sig`` in binary form. @@ -277,7 +285,7 @@ proc init*(key: var PrivateKey, data: openarray[byte]): bool = key = nkey result = true elif scheme == Secp256k1: - if init(nkey.skkey, buffer): + if init(nkey.skkey, buffer).isOk: key = nkey result = true @@ -308,7 +316,7 @@ proc init*(key: var PublicKey, data: openarray[byte]): bool = key = nkey result = true elif scheme == Secp256k1: - if init(nkey.skkey, buffer): + if init(nkey.skkey, buffer).isOk: key = nkey result = true @@ -325,50 +333,77 @@ proc init*(key: var PrivateKey, data: string): bool = ## hexadecimal string representation. ## ## Returns ``true`` on success. - result = key.init(fromHex(data)) + try: + key.init(fromHex(data)) + except ValueError: + false proc init*(key: var PublicKey, data: string): bool = ## Initialize public key ``key`` from libp2p's protobuf serialized ## hexadecimal string representation. ## ## Returns ``true`` on success. - result = key.init(fromHex(data)) + try: + key.init(fromHex(data)) + except ValueError: + false proc init*(sig: var Signature, data: string): bool = ## Initialize signature ``sig`` from serialized hexadecimal string ## representation. ## ## Returns ``true`` on success. - result = sig.init(fromHex(data)) + try: + sig.init(fromHex(data)) + except ValueError: + false -proc init*(t: typedesc[PrivateKey], data: openarray[byte]): PrivateKey = +proc init*(t: typedesc[PrivateKey], data: openarray[byte]): CryptoResult[PrivateKey] = ## Create new private key from libp2p's protobuf serialized binary form. - if not result.init(data): - raise newException(P2pKeyError, "Incorrect binary form") + var res: t + if not res.init(data): + err(KeyError) + else: + ok(res) -proc init*(t: typedesc[PublicKey], data: openarray[byte]): PublicKey = +proc init*(t: typedesc[PublicKey], data: openarray[byte]): CryptoResult[PublicKey] = ## Create new public key from libp2p's protobuf serialized binary form. - if not result.init(data): - raise newException(P2pKeyError, "Incorrect binary form") + var res: t + if not res.init(data): + err(KeyError) + else: + ok(res) -proc init*(t: typedesc[Signature], data: openarray[byte]): Signature = +proc init*(t: typedesc[Signature], data: openarray[byte]): CryptoResult[Signature] = ## Create new public key from libp2p's protobuf serialized binary form. - if not result.init(data): - raise newException(P2pSigError, "Incorrect binary form") + var res: t + if not res.init(data): + err(SigError) + else: + ok(res) -proc init*(t: typedesc[PrivateKey], data: string): PrivateKey = +proc init*(t: typedesc[PrivateKey], data: string): CryptoResult[PrivateKey] = ## Create new private key from libp2p's protobuf serialized hexadecimal string ## form. - result = t.init(fromHex(data)) + try: + t.init(fromHex(data)) + except ValueError: + err(KeyError) -proc init*(t: typedesc[PublicKey], data: string): PublicKey = +proc init*(t: typedesc[PublicKey], data: string): CryptoResult[PublicKey] = ## Create new public key from libp2p's protobuf serialized hexadecimal string ## form. - result = t.init(fromHex(data)) + try: + t.init(fromHex(data)) + except ValueError: + err(KeyError) -proc init*(t: typedesc[Signature], data: string): Signature = +proc init*(t: typedesc[Signature], data: string): CryptoResult[Signature] = ## Create new signature from serialized hexadecimal string form. - result = t.init(fromHex(data)) + try: + t.init(fromHex(data)) + except ValueError: + err(SigError) proc `==`*(key1, key2: PublicKey): bool = ## Return ``true`` if two public keys ``key1`` and ``key2`` of the same @@ -464,24 +499,30 @@ proc `$`*(sig: Signature): string = ## Get string representation of signature ``sig``. result = toHex(sig.data) -proc sign*(key: PrivateKey, data: openarray[byte]): Signature {.gcsafe.} = +proc sign*(key: PrivateKey, data: openarray[byte]): CryptoResult[Signature] {.gcsafe.} = ## Sign message ``data`` using private key ``key`` and return generated ## signature in raw binary form. + var res: Signature if key.scheme == RSA: - var sig = key.rsakey.sign(data) - result.data = sig.getBytes() + let sig = ? key.rsakey.sign(data).orError(SigError) + res.data = ? sig.getBytes().orError(SigError) + ok(res) elif key.scheme == Ed25519: - var sig = key.edkey.sign(data) - result.data = sig.getBytes() + let sig = key.edkey.sign(data) + res.data = sig.getBytes() + ok(res) elif key.scheme == ECDSA: - var sig = key.eckey.sign(data) - result.data = sig.getBytes() + let sig = ? key.eckey.sign(data).orError(SigError) + res.data = ? sig.getBytes().orError(SigError) + ok(res) elif key.scheme == Secp256k1: - var sig = key.skkey.sign(data) - result.data = sig.getBytes() + let sig = ? key.skkey.sign(data).orError(SigError) + res.data = sig.getBytes() + ok(res) + else: + err(SigError) -proc verify*(sig: Signature, message: openarray[byte], - key: PublicKey): bool = +proc verify*(sig: Signature, message: openarray[byte], key: PublicKey): bool = ## Verify signature ``sig`` using message ``message`` and public key ``key``. ## Return ``true`` if message signature is valid. if key.scheme == RSA: @@ -498,7 +539,7 @@ proc verify*(sig: Signature, message: openarray[byte], result = signature.verify(message, key.eckey) elif key.scheme == Secp256k1: var signature: SkSignature - if signature.init(sig.data): + if signature.init(sig.data).isOk: result = signature.verify(message, key.skkey) template makeSecret(buffer, hmactype, secret, seed: untyped) {.dirty.}= @@ -510,11 +551,11 @@ template makeSecret(buffer, hmactype, secret, seed: untyped) {.dirty.}= if secret[i] != 0x00'u8: break inc(offset) - ctx.init(secret.toOpenArray(offset, len(secret) - 1)) + ctx.init(secret.toOpenArray(offset, secret.high)) ctx.update(seed) var a = ctx.finish() while j < len(buffer): - ctx.init(secret.toOpenArray(offset, len(secret) - 1)) + ctx.init(secret.toOpenArray(offset, secret.high)) ctx.update(a.data) ctx.update(seed) var b = ctx.finish() @@ -523,7 +564,7 @@ template makeSecret(buffer, hmactype, secret, seed: untyped) {.dirty.}= todo = len(buffer) - j copyMem(addr buffer[j], addr b.data[0], todo) j += todo - ctx.init(secret.toOpenArray(offset, len(secret) - 1)) + ctx.init(secret.toOpenArray(offset, secret.high)) ctx.update(a.data) a = ctx.finish() @@ -588,33 +629,32 @@ proc mac*(secret: Secret, id: int): seq[byte] {.inline.} = offset += secret.ivsize + secret.keysize copyMem(addr result[0], unsafeAddr secret.data[offset], secret.macsize) -proc ephemeral*(scheme: ECDHEScheme): KeyPair = +proc ephemeral*(scheme: ECDHEScheme): CryptoResult[KeyPair] = ## Generate ephemeral keys used to perform ECDHE. var keypair: EcKeyPair if scheme == Secp256r1: - keypair = EcKeyPair.random(Secp256r1) + keypair = ? EcKeyPair.random(Secp256r1).orError(KeyError) elif scheme == Secp384r1: - keypair = EcKeyPair.random(Secp384r1) + keypair = ? EcKeyPair.random(Secp384r1).orError(KeyError) elif scheme == Secp521r1: - keypair = EcKeyPair.random(Secp521r1) - result.seckey = PrivateKey(scheme: ECDSA) - result.pubkey = PublicKey(scheme: ECDSA) - result.seckey.eckey = keypair.seckey - result.pubkey.eckey = keypair.pubkey + keypair = ? EcKeyPair.random(Secp521r1).orError(KeyError) + ok(KeyPair( + seckey: PrivateKey(scheme: ECDSA, eckey: keypair.seckey), + pubkey: PublicKey(scheme: ECDSA, eckey: keypair.pubkey))) -proc ephemeral*(scheme: string): KeyPair {.inline.} = +proc ephemeral*(scheme: string): CryptoResult[KeyPair] {.inline.} = ## Generate ephemeral keys used to perform ECDHE using string encoding. ## ## Currently supported encoding strings are P-256, P-384, P-521, if encoding ## string is not supported P-521 key will be generated. if scheme == "P-256": - result = ephemeral(Secp256r1) + ephemeral(Secp256r1) elif scheme == "P-384": - result = ephemeral(Secp384r1) + ephemeral(Secp384r1) elif scheme == "P-521": - result = ephemeral(Secp521r1) + ephemeral(Secp521r1) else: - result = ephemeral(Secp521r1) + ephemeral(Secp521r1) proc makeSecret*(remoteEPublic: PublicKey, localEPrivate: PrivateKey, data: var openarray[byte]): int = @@ -644,7 +684,7 @@ proc getSecret*(remoteEPublic: PublicKey, result = getSecret(remoteEPublic.eckey, localEPrivate.eckey) proc getOrder*(remotePubkey, localNonce: openarray[byte], - localPubkey, remoteNonce: openarray[byte]): int = + localPubkey, remoteNonce: openarray[byte]): CryptoResult[int] = ## Compare values and calculate `order` parameter. var ctx: sha256 ctx.init() @@ -655,16 +695,18 @@ proc getOrder*(remotePubkey, localNonce: openarray[byte], ctx.update(localPubkey) ctx.update(remoteNonce) var digest2 = ctx.finish() - var mh1 = MultiHash.init(multiCodec("sha2-256"), digest1) - var mh2 = MultiHash.init(multiCodec("sha2-256"), digest2) + var mh1 = ? MultiHash.init(multiCodec("sha2-256"), digest1).orError(HashError) + var mh2 = ? MultiHash.init(multiCodec("sha2-256"), digest2).orError(HashError) + var res = 0; for i in 0 ..< len(mh1.data.buffer): - result = int(mh1.data.buffer[i]) - int(mh2.data.buffer[i]) - if result != 0: - if result < 0: - result = -1 - elif result > 0: - result = 1 + res = int(mh1.data.buffer[i]) - int(mh2.data.buffer[i]) + if res != 0: + if res < 0: + res = -1 + elif res > 0: + res = 1 break + ok(res) proc selectBest*(order: int, p1, p2: string): string = ## Determines which algorithm to use from list `p1` and `p2`. @@ -741,25 +783,25 @@ proc decodeExchange*(message: seq[byte], ## Serialization/Deserialization helpers -proc write*(vb: var VBuffer, pubkey: PublicKey) {.inline.} = +proc write*(vb: var VBuffer, pubkey: PublicKey) {.inline, raises: [Defect, ResultError[CryptoError]].} = ## Write PublicKey value ``pubkey`` to buffer ``vb``. - vb.writeSeq(pubkey.getBytes()) + vb.writeSeq(pubkey.getBytes().tryGet()) -proc write*(vb: var VBuffer, seckey: PrivateKey) {.inline.} = +proc write*(vb: var VBuffer, seckey: PrivateKey) {.inline, raises: [Defect, ResultError[CryptoError]].} = ## Write PrivateKey value ``seckey`` to buffer ``vb``. - vb.writeSeq(seckey.getBytes()) + vb.writeSeq(seckey.getBytes().tryGet()) -proc write*(vb: var VBuffer, sig: PrivateKey) {.inline.} = +proc write*(vb: var VBuffer, sig: PrivateKey) {.inline, raises: [Defect, ResultError[CryptoError]].} = ## Write Signature value ``sig`` to buffer ``vb``. - vb.writeSeq(sig.getBytes()) + vb.writeSeq(sig.getBytes().tryGet()) -proc initProtoField*(index: int, pubkey: PublicKey): ProtoField = +proc initProtoField*(index: int, pubkey: PublicKey): ProtoField {.raises: [Defect, ResultError[CryptoError]].} = ## Initialize ProtoField with PublicKey ``pubkey``. - result = initProtoField(index, pubkey.getBytes()) + result = initProtoField(index, pubkey.getBytes().tryGet()) -proc initProtoField*(index: int, seckey: PrivateKey): ProtoField = +proc initProtoField*(index: int, seckey: PrivateKey): ProtoField {.raises: [Defect, ResultError[CryptoError]].} = ## Initialize ProtoField with PrivateKey ``seckey``. - result = initProtoField(index, seckey.getBytes()) + result = initProtoField(index, seckey.getBytes().tryGet()) proc initProtoField*(index: int, sig: Signature): ProtoField = ## Initialize ProtoField with Signature ``sig``. diff --git a/libp2p/crypto/ecnist.nim b/libp2p/crypto/ecnist.nim index 645e9556e..03209305b 100644 --- a/libp2p/crypto/ecnist.nim +++ b/libp2p/crypto/ecnist.nim @@ -14,6 +14,8 @@ ## BearSSL library ## Copyright(C) 2018 Thomas Pornin . +{.push raises: [Defect].} + import bearssl import nimcrypto/utils import minasn1 @@ -58,11 +60,14 @@ type EcPKI* = EcPrivateKey | EcPublicKey | EcSignature - EcError* = object of CatchableError - EcKeyIncorrectError* = object of EcError - EcRngError* = object of EcError - EcPublicKeyError* = object of EcError - EcSignatureError* = object of EcError + EcError* = enum + EcRngError, + EcKeyGenError, + EcPublicKeyError, + EcKeyIncorrectError, + EcSignatureError + + EcResult*[T] = Result[T, EcError] const EcSupportedCurvesCint* = {cint(Secp256r1), cint(Secp384r1), cint(Secp521r1)} @@ -222,7 +227,7 @@ proc clear*[T: EcPKI|EcKeyPair](pki: var T) = pki.pubkey.key.qlen = 0 pki.pubkey.key.curve = 0 -proc random*(t: typedesc[EcPrivateKey], kind: EcCurveKind): EcPrivateKey = +proc random*(t: typedesc[EcPrivateKey], kind: EcCurveKind): EcResult[EcPrivateKey] = ## Generate new random EC private key using BearSSL's HMAC-SHA256-DRBG ## algorithm. ## @@ -232,37 +237,46 @@ proc random*(t: typedesc[EcPrivateKey], kind: EcCurveKind): EcPrivateKey = var seeder = brPrngSeederSystem(nil) brHmacDrbgInit(addr rng, addr sha256Vtable, nil, 0) if seeder(addr rng.vtable) == 0: - raise newException(ValueError, "Could not seed RNG") + return err(EcRngError) var ecimp = brEcGetDefault() - result = new EcPrivateKey - result.buffer = newSeq[byte](BR_EC_KBUF_PRIV_MAX_SIZE) + var res = new EcPrivateKey + res.buffer = newSeq[byte](BR_EC_KBUF_PRIV_MAX_SIZE) if brEcKeygen(addr rng.vtable, ecimp, - addr result.key, addr result.buffer[0], + addr res.key, addr res.buffer[0], cast[cint](kind)) == 0: - raise newException(ValueError, "Could not generate private key") + err(EcKeyGenError) + else: + ok(res) -proc getKey*(seckey: EcPrivateKey): EcPublicKey = +proc getKey*(seckey: EcPrivateKey): EcResult[EcPublicKey] = ## Calculate and return EC public key from private key ``seckey``. - doAssert(not isNil(seckey)) + if isNil(seckey): + return err(EcKeyIncorrectError) + var ecimp = brEcGetDefault() if seckey.key.curve in EcSupportedCurvesCint: var length = getPublicKeyLength(cast[EcCurveKind](seckey.key.curve)) - result = new EcPublicKey - result.buffer = newSeq[byte](length) - if brEcComputePublicKey(ecimp, addr result.key, - addr result.buffer[0], unsafeAddr seckey.key) == 0: - raise newException(EcKeyIncorrectError, "Could not calculate public key") + var res = new EcPublicKey + res.buffer = newSeq[byte](length) + if brEcComputePublicKey(ecimp, addr res.key, + addr res.buffer[0], unsafeAddr seckey.key) == 0: + err(EcKeyIncorrectError) + else: + ok(res) else: - raise newException(EcKeyIncorrectError, "Incorrect private key") + err(EcKeyIncorrectError) -proc random*(t: typedesc[EcKeyPair], kind: EcCurveKind): EcKeyPair {.inline.} = +proc random*(t: typedesc[EcKeyPair], kind: EcCurveKind): EcResult[EcKeyPair] = ## Generate new random EC private and public keypair using BearSSL's ## HMAC-SHA256-DRBG algorithm. ## ## ``kind`` elliptic curve kind of your choice (secp256r1, secp384r1 or ## secp521r1). - result.seckey = EcPrivateKey.random(kind) - result.pubkey = result.seckey.getKey() + let + seckey = ? EcPrivateKey.random(kind) + pubkey = ? seckey.getKey() + key = EcKeyPair(seckey: seckey, pubkey: pubkey) + ok(key) proc `$`*(seckey: EcPrivateKey): string = ## Return string representation of EC private key. @@ -303,29 +317,37 @@ proc `$`*(sig: EcSignature): string = else: result = toHex(sig.buffer) -proc toRawBytes*(seckey: EcPrivateKey, data: var openarray[byte]): int = +proc toRawBytes*(seckey: EcPrivateKey, data: var openarray[byte]): EcResult[int] = ## Serialize EC private key ``seckey`` to raw binary form and store it ## to ``data``. ## ## Returns number of bytes (octets) needed to store EC private key, or `0` ## if private key is not in supported curve. - doAssert(not isNil(seckey)) + if isNil(seckey): + return err(EcKeyIncorrectError) if seckey.key.curve in EcSupportedCurvesCint: - result = getPrivateKeyLength(cast[EcCurveKind](seckey.key.curve)) - if len(data) >= result: - copyMem(addr data[0], unsafeAddr seckey.buffer[0], result) + let klen = getPrivateKeyLength(cast[EcCurveKind](seckey.key.curve)) + if len(data) >= klen: + copyMem(addr data[0], unsafeAddr seckey.buffer[0], klen) + ok(klen) + else: + err(EcKeyIncorrectError) -proc toRawBytes*(pubkey: EcPublicKey, data: var openarray[byte]): int = +proc toRawBytes*(pubkey: EcPublicKey, data: var openarray[byte]): EcResult[int] = ## Serialize EC public key ``pubkey`` to uncompressed form specified in ## section 4.3.6 of ANSI X9.62. ## ## Returns number of bytes (octets) needed to store EC public key, or `0` ## if public key is not in supported curve. - doAssert(not isNil(pubkey)) + if isNil(pubkey): + return err(EcKeyIncorrectError) if pubkey.key.curve in EcSupportedCurvesCint: - result = getPublicKeyLength(cast[EcCurveKind](pubkey.key.curve)) - if len(data) >= result: - copyMem(addr data[0], unsafeAddr pubkey.buffer[0], result) + let klen = getPublicKeyLength(cast[EcCurveKind](pubkey.key.curve)) + if len(data) >= klen: + copyMem(addr data[0], unsafeAddr pubkey.buffer[0], klen) + ok(klen) + else: + err(EcKeyIncorrectError) proc toRawBytes*(sig: EcSignature, data: var openarray[byte]): int = ## Serialize EC signature ``sig`` to raw binary form and store it to ``data``. @@ -338,16 +360,17 @@ proc toRawBytes*(sig: EcSignature, data: var openarray[byte]): int = if len(sig.buffer) > 0: copyMem(addr data[0], unsafeAddr sig.buffer[0], len(sig.buffer)) -proc toBytes*(seckey: EcPrivateKey, data: var openarray[byte]): int = +proc toBytes*(seckey: EcPrivateKey, data: var openarray[byte]): EcResult[int] = ## Serialize EC private key ``seckey`` to ASN.1 DER binary form and store it ## to ``data``. ## ## Procedure returns number of bytes (octets) needed to store EC private key, ## or `0` if private key is not in supported curve. - doAssert(not isNil(seckey)) + if isNil(seckey): + return err(EcKeyIncorrectError) if seckey.key.curve in EcSupportedCurvesCint: var offset, length: int - var pubkey = seckey.getKey() + var pubkey = ? seckey.getKey() var b = Asn1Buffer.init() var p = Asn1Composite.init(Asn1Tag.Sequence) var c0 = Asn1Composite.init(0) @@ -374,17 +397,23 @@ proc toBytes*(seckey: EcPrivateKey, data: var openarray[byte]): int = p.finish() b.write(p) b.finish() - result = len(b) - if len(data) >= result: - copyMem(addr data[0], addr b.buffer[0], result) + var blen = len(b) + if len(data) >= blen: + copyMem(addr data[0], addr b.buffer[0], blen) + # ok anyway, since it might have been a query... + ok(blen) + else: + err(EcKeyIncorrectError) -proc toBytes*(pubkey: EcPublicKey, data: var openarray[byte]): int = + +proc toBytes*(pubkey: EcPublicKey, data: var openarray[byte]): EcResult[int] = ## Serialize EC public key ``pubkey`` to ASN.1 DER binary form and store it ## to ``data``. ## ## Procedure returns number of bytes (octets) needed to store EC public key, ## or `0` if public key is not in supported curve. - doAssert(not isNil(pubkey)) + if isNil(pubkey): + return err(EcKeyIncorrectError) if pubkey.key.curve in EcSupportedCurvesCint: var b = Asn1Buffer.init() var p = Asn1Composite.init(Asn1Tag.Sequence) @@ -405,80 +434,97 @@ proc toBytes*(pubkey: EcPublicKey, data: var openarray[byte]): int = p.finish() b.write(p) b.finish() - result = len(b) - if len(data) >= result: - copyMem(addr data[0], addr b.buffer[0], result) + var blen = len(b) + if len(data) >= blen: + copyMem(addr data[0], addr b.buffer[0], blen) + ok(blen) + else: + err(EcKeyIncorrectError) -proc toBytes*(sig: EcSignature, data: var openarray[byte]): int = +proc toBytes*(sig: EcSignature, data: var openarray[byte]): EcResult[int] = ## Serialize EC signature ``sig`` to ASN.1 DER binary form and store it ## to ``data``. ## ## Procedure returns number of bytes (octets) needed to store EC signature, ## or `0` if signature is not in supported curve. - doAssert(not isNil(sig)) - result = len(sig.buffer) - if len(data) >= result: - copyMem(addr data[0], unsafeAddr sig.buffer[0], result) + if isNil(sig): + return err(EcSignatureError) + let slen = len(sig.buffer) + if len(data) >= slen: + copyMem(addr data[0], unsafeAddr sig.buffer[0], slen) + ok(slen) -proc getBytes*(seckey: EcPrivateKey): seq[byte] = +proc getBytes*(seckey: EcPrivateKey): EcResult[seq[byte]] = ## Serialize EC private key ``seckey`` to ASN.1 DER binary form and return it. - doAssert(not isNil(seckey)) + if isNil(seckey): + return err(EcKeyIncorrectError) if seckey.key.curve in EcSupportedCurvesCint: - result = newSeq[byte]() - let length = seckey.toBytes(result) - result.setLen(length) - discard seckey.toBytes(result) + var res = newSeq[byte]() + let length = ? seckey.toBytes(res) + res.setLen(length) + discard ? seckey.toBytes(res) + ok(res) else: - raise newException(EcKeyIncorrectError, "Incorrect private key") + err(EcKeyIncorrectError) -proc getBytes*(pubkey: EcPublicKey): seq[byte] = +proc getBytes*(pubkey: EcPublicKey): EcResult[seq[byte]] = ## Serialize EC public key ``pubkey`` to ASN.1 DER binary form and return it. - doAssert(not isNil(pubkey)) + if isNil(pubkey): + return err(EcKeyIncorrectError) if pubkey.key.curve in EcSupportedCurvesCint: - result = newSeq[byte]() - let length = pubkey.toBytes(result) - result.setLen(length) - discard pubkey.toBytes(result) + var res = newSeq[byte]() + let length = ? pubkey.toBytes(res) + res.setLen(length) + discard ? pubkey.toBytes(res) + ok(res) else: - raise newException(EcKeyIncorrectError, "Incorrect public key") + err(EcKeyIncorrectError) -proc getBytes*(sig: EcSignature): seq[byte] = +proc getBytes*(sig: EcSignature): EcResult[seq[byte]] = ## Serialize EC signature ``sig`` to ASN.1 DER binary form and return it. - doAssert(not isNil(sig)) - result = newSeq[byte]() - let length = sig.toBytes(result) - result.setLen(length) - discard sig.toBytes(result) + if isNil(sig): + return err(EcSignatureError) + var res = newSeq[byte]() + let length = ? sig.toBytes(res) + res.setLen(length) + discard ? sig.toBytes(res) + ok(res) -proc getRawBytes*(seckey: EcPrivateKey): seq[byte] = +proc getRawBytes*(seckey: EcPrivateKey): EcResult[seq[byte]] = ## Serialize EC private key ``seckey`` to raw binary form and return it. - doAssert(not isNil(seckey)) + if isNil(seckey): + return err(EcKeyIncorrectError) if seckey.key.curve in EcSupportedCurvesCint: - result = newSeq[byte]() - let length = seckey.toRawBytes(result) - result.setLen(length) - discard seckey.toRawBytes(result) + var res = newSeq[byte]() + let length = ? seckey.toRawBytes(res) + res.setLen(length) + discard ? seckey.toRawBytes(res) + ok(res) else: - raise newException(EcKeyIncorrectError, "Incorrect private key") + err(EcKeyIncorrectError) -proc getRawBytes*(pubkey: EcPublicKey): seq[byte] = +proc getRawBytes*(pubkey: EcPublicKey): EcResult[seq[byte]] = ## Serialize EC public key ``pubkey`` to raw binary form and return it. - doAssert(not isNil(pubkey)) + if isNil(pubkey): + return err(EcKeyIncorrectError) if pubkey.key.curve in EcSupportedCurvesCint: - result = newSeq[byte]() - let length = pubkey.toRawBytes(result) - result.setLen(length) - discard pubkey.toRawBytes(result) + var res = newSeq[byte]() + let length = ? pubkey.toRawBytes(res) + res.setLen(length) + discard ? pubkey.toRawBytes(res) + ok(res) else: - raise newException(EcKeyIncorrectError, "Incorrect public key") + return err(EcKeyIncorrectError) -proc getRawBytes*(sig: EcSignature): seq[byte] = +proc getRawBytes*(sig: EcSignature): EcResult[seq[byte]] = ## Serialize EC signature ``sig`` to raw binary form and return it. - doAssert(not isNil(sig)) - result = newSeq[byte]() - let length = sig.toBytes(result) - result.setLen(length) - discard sig.toBytes(result) + if isNil(sig): + return err(EcSignatureError) + var res = newSeq[byte]() + let length = ? sig.toBytes(res) + res.setLen(length) + discard ? sig.toBytes(res) + ok(res) proc `==`*(pubkey1, pubkey2: EcPublicKey): bool = ## Returns ``true`` if both keys ``pubkey1`` and ``pubkey2`` are equal. @@ -663,34 +709,43 @@ proc init*[T: EcPKI](sospk: var T, data: string): Result[void, Asn1Error] {.inli ## Procedure returns ``Asn1Status``. sospk.init(fromHex(data)) -proc init*(t: typedesc[EcPrivateKey], data: openarray[byte]): EcPrivateKey = +proc init*(t: typedesc[EcPrivateKey], data: openarray[byte]): EcResult[EcPrivateKey] = ## Initialize EC private key from ASN.1 DER binary representation ``data`` and ## return constructed object. - let res = result.init(data) + var key: EcPrivateKey + let res = key.init(data) if res.isErr: - raise newException(EcKeyIncorrectError, - "Incorrect private key (" & $res.error & ")") + err(EcKeyIncorrectError) + else: + ok(key) -proc init*(t: typedesc[EcPublicKey], data: openarray[byte]): EcPublicKey = +proc init*(t: typedesc[EcPublicKey], data: openarray[byte]): EcResult[EcPublicKey] = ## Initialize EC public key from ASN.1 DER binary representation ``data`` and ## return constructed object. - let res = result.init(data) + var key: EcPublicKey + let res = key.init(data) if res.isErr: - raise newException(EcKeyIncorrectError, - "Incorrect public key (" & $res.error & ")") + err(EcKeyIncorrectError) + else: + ok(key) -proc init*(t: typedesc[EcSignature], data: openarray[byte]): EcSignature = +proc init*(t: typedesc[EcSignature], data: openarray[byte]): EcResult[EcSignature] = ## Initialize EC signature from raw binary representation ``data`` and ## return constructed object. - let res = result.init(data) + var sig: EcSignature + let res = sig.init(data) if res.isErr: - raise newException(EcKeyIncorrectError, - "Incorrect signature (" & $res.error & ")") + err(EcSignatureError) + else: + ok(sig) -proc init*[T: EcPKI](t: typedesc[T], data: string): T {.inline.} = +proc init*[T: EcPKI](t: typedesc[T], data: string): EcResult[T] = ## Initialize EC `private key`, `public key` or `signature` from hexadecimal ## string representation ``data`` and return constructed object. - result = t.init(fromHex(data)) + try: + t.init(fromHex(data)) + except ValueError: + err(EcKeyIncorrectError) proc initRaw*(key: var EcPrivateKey, data: openarray[byte]): bool = ## Initialize EC `private key` or `scalar` ``key`` from raw binary @@ -776,23 +831,32 @@ proc initRaw*[T: EcPKI](sospk: var T, data: string): bool {.inline.} = ## Procedure returns ``true`` on success, ``false`` otherwise. result = sospk.initRaw(fromHex(data)) -proc initRaw*(t: typedesc[EcPrivateKey], data: openarray[byte]): EcPrivateKey = +proc initRaw*(t: typedesc[EcPrivateKey], data: openarray[byte]): EcResult[EcPrivateKey] = ## Initialize EC private key from raw binary representation ``data`` and ## return constructed object. - if not result.initRaw(data): - raise newException(EcKeyIncorrectError, "Incorrect private key") + var res: EcPrivateKey + if not res.initRaw(data): + err(EcKeyIncorrectError) + else: + ok(res) -proc initRaw*(t: typedesc[EcPublicKey], data: openarray[byte]): EcPublicKey = +proc initRaw*(t: typedesc[EcPublicKey], data: openarray[byte]): EcResult[EcPublicKey] = ## Initialize EC public key from raw binary representation ``data`` and ## return constructed object. - if not result.initRaw(data): - raise newException(EcKeyIncorrectError, "Incorrect public key") + var res: EcPublicKey + if not res.initRaw(data): + err(EcKeyIncorrectError) + else: + ok(res) -proc initRaw*(t: typedesc[EcSignature], data: openarray[byte]): EcSignature = +proc initRaw*(t: typedesc[EcSignature], data: openarray[byte]): EcResult[EcSignature] = ## Initialize EC signature from raw binary representation ``data`` and ## return constructed object. - if not result.initRaw(data): - raise newException(EcKeyIncorrectError, "Incorrect signature") + var res: EcSignature + if not res.initRaw(data): + err(EcSignatureError) + else: + ok(res) proc initRaw*[T: EcPKI](t: typedesc[T], data: string): T {.inline.} = ## Initialize EC `private key`, `public key` or `signature` from raw @@ -858,15 +922,16 @@ proc getSecret*(pubkey: EcPublicKey, seckey: EcPrivateKey): seq[byte] = copyMem(addr result[0], addr data[0], res) proc sign*[T: byte|char](seckey: EcPrivateKey, - message: openarray[T]): EcSignature {.gcsafe.} = + message: openarray[T]): EcResult[EcSignature] {.gcsafe.} = ## Get ECDSA signature of data ``message`` using private key ``seckey``. - doAssert(not isNil(seckey)) + if isNil(seckey): + return err(EcKeyIncorrectError) var hc: BrHashCompatContext var hash: array[32, byte] var impl = brEcGetDefault() if seckey.key.curve in EcSupportedCurvesCint: - result = new EcSignature - result.buffer = newSeq[byte](256) + var sig = new EcSignature + sig.buffer = newSeq[byte](256) var kv = addr sha256Vtable kv.init(addr hc.vtable) if len(message) > 0: @@ -875,15 +940,16 @@ proc sign*[T: byte|char](seckey: EcPrivateKey, kv.update(addr hc.vtable, nil, 0) kv.output(addr hc.vtable, addr hash[0]) let res = brEcdsaSignAsn1(impl, kv, addr hash[0], addr seckey.key, - addr result.buffer[0]) + addr sig.buffer[0]) # Clear context with initial value kv.init(addr hc.vtable) if res != 0: - result.buffer.setLen(res) + sig.buffer.setLen(res) + ok(sig) else: - raise newException(EcSignatureError, "Could not make signature") + err(EcSignatureError) else: - raise newException(EcKeyIncorrectError, "Incorrect private key") + err(EcKeyIncorrectError) proc verify*[T: byte|char](sig: EcSignature, message: openarray[T], pubkey: EcPublicKey): bool {.inline.} = diff --git a/libp2p/crypto/ed25519/ed25519.nim b/libp2p/crypto/ed25519/ed25519.nim index 20c17b7ea..64305fd4e 100644 --- a/libp2p/crypto/ed25519/ed25519.nim +++ b/libp2p/crypto/ed25519/ed25519.nim @@ -10,8 +10,13 @@ ## This module implements ED25519. ## This code is a port of the public domain, "ref10" implementation of ed25519 ## from SUPERCOP. + +{.push raises: Defect.} + import constants import nimcrypto/[hash, sha2, sysrand, utils] +import stew/results +export results # This workaround needed because of some bugs in Nim Static[T]. export hash, sha2 @@ -38,9 +43,9 @@ type seckey*: EdPrivateKey pubkey*: EdPublicKey - EdError* = object of CatchableError - EdRngError* = object of EdError - EdIncorrectError* = object of EdError + EdError* = enum + EdRngError, + EdIncorrectError proc `-`(x: uint32): uint32 {.inline.} = result = (0xFFFF_FFFF'u32 - x) + 1'u32 @@ -1632,40 +1637,47 @@ proc checkScalar*(scalar: openarray[byte]): uint32 = for u in scalar: z = z or u if len(scalar) == len(CurveOrder): - for i in countdown(len(scalar) - 1, 0): + for i in countdown(scalar.high, 0): c = c or (-(cast[int32](EQ0(c))) and CMP(scalar[i], CurveOrder[i])) else: c = -1 result = NEQ(z, 0'u32) and LT0(c) -proc random*(t: typedesc[EdPrivateKey]): EdPrivateKey = +proc random*(t: typedesc[EdPrivateKey]): Result[EdPrivateKey, EdError] = ## Generate new random ED25519 private key using OS specific CSPRNG. var point: GeP3 pk: array[EdPublicKeySize, byte] - if randomBytes(result.data.toOpenArray(0, 31)) != 32: - raise newException(EdRngError, "Could not generate random data") - var hh = sha512.digest(result.data.toOpenArray(0, 31)) - hh.data[0] = hh.data[0] and 0xF8'u8 - hh.data[31] = hh.data[31] and 0x3F'u8 - hh.data[31] = hh.data[31] or 0x40'u8 - geScalarMultBase(point, hh.data) - geP3ToBytes(pk, point) - copyMem(addr result.data[32], addr pk[0], 32) + res: EdPrivateKey + if randomBytes(res.data.toOpenArray(0, 31)) != 32: + err(EdRngError) + else: + var hh = sha512.digest(res.data.toOpenArray(0, 31)) + hh.data[0] = hh.data[0] and 0xF8'u8 + hh.data[31] = hh.data[31] and 0x3F'u8 + hh.data[31] = hh.data[31] or 0x40'u8 + geScalarMultBase(point, hh.data) + geP3ToBytes(pk, point) + copyMem(addr res.data[32], addr pk[0], 32) + ok(res) -proc random*(t: typedesc[EdKeyPair]): EdKeyPair = +proc random*(t: typedesc[EdKeyPair]): Result[EdKeyPair, EdError] = ## Generate new random ED25519 private and public keypair using OS specific ## CSPRNG. - var point: GeP3 - if randomBytes(result.seckey.data.toOpenArray(0, 31)) != 32: - raise newException(EdRngError, "Could not generate random data") - var hh = sha512.digest(result.seckey.data.toOpenArray(0, 31)) - hh.data[0] = hh.data[0] and 0xF8'u8 - hh.data[31] = hh.data[31] and 0x3F'u8 - hh.data[31] = hh.data[31] or 0x40'u8 - geScalarMultBase(point, hh.data) - geP3ToBytes(result.pubkey.data, point) - copyMem(addr result.seckey.data[32], addr result.pubkey.data[0], 32) + var + point: GeP3 + res: EdKeyPair + if randomBytes(res.seckey.data.toOpenArray(0, 31)) != 32: + err(EdRngError) + else: + var hh = sha512.digest(res.seckey.data.toOpenArray(0, 31)) + hh.data[0] = hh.data[0] and 0xF8'u8 + hh.data[31] = hh.data[31] and 0x3F'u8 + hh.data[31] = hh.data[31] or 0x40'u8 + geScalarMultBase(point, hh.data) + geP3ToBytes(res.pubkey.data, point) + copyMem(addr res.seckey.data[32], addr res.pubkey.data[0], 32) + ok(res) proc getKey*(key: EdPrivateKey): EdPublicKey = ## Calculate and return ED25519 public key from private key ``key``. @@ -1766,57 +1778,84 @@ proc init*(key: var EdPrivateKey, data: string): bool = ## representation ``data``. ## ## Procedure returns ``true`` on success. - result = init(key, fromHex(data)) + try: + init(key, fromHex(data)) + except ValueError: + false proc init*(key: var EdPublicKey, data: string): bool = ## Initialize ED25519 `public key` ``key`` from hexadecimal string ## representation ``data``. ## ## Procedure returns ``true`` on success. - result = init(key, fromHex(data)) + try: + init(key, fromHex(data)) + except ValueError: + false proc init*(sig: var EdSignature, data: string): bool = ## Initialize ED25519 `signature` ``sig`` from hexadecimal string ## representation ``data``. ## ## Procedure returns ``true`` on success. - result = init(sig, fromHex(data)) + try: + init(sig, fromHex(data)) + except ValueError: + false -proc init*(t: typedesc[EdPrivateKey], data: openarray[byte]): EdPrivateKey = +proc init*(t: typedesc[EdPrivateKey], data: openarray[byte]): Result[EdPrivateKey, EdError] = ## Initialize ED25519 `private key` from raw binary representation ``data`` ## and return constructed object. - if not init(result, data): - raise newException(EdIncorrectError, "Incorrect binary form") + var res: t + if not init(res, data): + err(EdIncorrectError) + else: + ok(res) -proc init*(t: typedesc[EdPublicKey], data: openarray[byte]): EdPublicKey = +proc init*(t: typedesc[EdPublicKey], data: openarray[byte]): Result[EdPublicKey, EdError] = ## Initialize ED25519 `public key` from raw binary representation ``data`` ## and return constructed object. - if not init(result, data): - raise newException(EdIncorrectError, "Incorrect binary form") + var res: t + if not init(res, data): + err(EdIncorrectError) + else: + ok(res) -proc init*(t: typedesc[EdSignature], data: openarray[byte]): EdSignature = +proc init*(t: typedesc[EdSignature], data: openarray[byte]): Result[EdSignature, EdError] = ## Initialize ED25519 `signature` from raw binary representation ``data`` ## and return constructed object. - if not init(result, data): - raise newException(EdIncorrectError, "Incorrect binary form") + var res: t + if not init(res, data): + err(EdIncorrectError) + else: + ok(res) -proc init*(t: typedesc[EdPrivateKey], data: string): EdPrivateKey = +proc init*(t: typedesc[EdPrivateKey], data: string): Result[EdPrivateKey, EdError] = ## Initialize ED25519 `private key` from hexadecimal string representation ## ``data`` and return constructed object. - if not init(result, data): - raise newException(EdIncorrectError, "Incorrect binary form") + var res: t + if not init(res, data): + err(EdIncorrectError) + else: + ok(res) -proc init*(t: typedesc[EdPublicKey], data: string): EdPublicKey = +proc init*(t: typedesc[EdPublicKey], data: string): Result[EdPublicKey, EdError] = ## Initialize ED25519 `public key` from hexadecimal string representation ## ``data`` and return constructed object. - if not init(result, data): - raise newException(EdIncorrectError, "Incorrect binary form") + var res: t + if not init(res, data): + err(EdIncorrectError) + else: + ok(res) -proc init*(t: typedesc[EdSignature], data: string): EdSignature = +proc init*(t: typedesc[EdSignature], data: string): Result[EdSignature, EdError] = ## Initialize ED25519 `signature` from hexadecimal string representation ## ``data`` and return constructed object. - if not init(result, data): - raise newException(EdIncorrectError, "Incorrect binary form") + var res: t + if not init(res, data): + err(EdIncorrectError) + else: + ok(res) proc clear*(key: var EdPrivateKey) = ## Wipe and clear memory of ED25519 `private key`. diff --git a/libp2p/crypto/minasn1.nim b/libp2p/crypto/minasn1.nim index a8bc6e03a..63545f221 100644 --- a/libp2p/crypto/minasn1.nim +++ b/libp2p/crypto/minasn1.nim @@ -106,10 +106,10 @@ const ## Encoded ``NULL`` value. template toOpenArray*(ab: Asn1Buffer): untyped = - toOpenArray(ab.buffer, ab.offset, len(ab.buffer) - 1) + toOpenArray(ab.buffer, ab.offset, ab.buffer.high) template toOpenArray*(ac: Asn1Composite): untyped = - toOpenArray(ac.buffer, ac.offset, len(ac.buffer) - 1) + toOpenArray(ac.buffer, ac.offset, ac.buffer.high) template toOpenArray*(af: Asn1Field): untyped = toOpenArray(af.buffer, af.offset, af.offset + af.length - 1) @@ -336,7 +336,7 @@ proc asn1EncodeOid*(dest: var openarray[byte], value: openarray[int]): int = result += asn1EncodeLength(buffer, oidlen) result += oidlen if len(dest) >= result: - let last = len(dest) - 1 + let last = dest.high var offset = 1 dest[0] = Asn1Tag.Oid.code() offset += asn1EncodeLength(dest.toOpenArray(offset, last), oidlen) diff --git a/libp2p/crypto/rsa.nim b/libp2p/crypto/rsa.nim index 79be34e2a..5f40140c2 100644 --- a/libp2p/crypto/rsa.nim +++ b/libp2p/crypto/rsa.nim @@ -12,6 +12,9 @@ ## This module uses unmodified parts of code from ## BearSSL library ## Copyright(C) 2018 Thomas Pornin . + +{.push raises: Defect.} + import nimcrypto/utils import bearssl import minasn1 @@ -72,11 +75,13 @@ type RsaPKI* = RsaPrivateKey | RsaPublicKey | RsaSignature RsaKP* = RsaPrivateKey | RsaKeyPair - RsaError* = object of CatchableError - RsaRngError* = object of RsaError - RsaGenError* = object of RsaError - RsaKeyIncorrectError* = object of RsaError - RsaSignatureError* = object of RsaError + RsaError* = enum + RsaRngError, + RsaGenError, + RsaKeyIncorrectError, + RsaSignatureError + + RsaResult*[T] = Result[T, RsaError] template getStart(bs, os, ls: untyped): untyped = let p = cast[uint](os) @@ -108,7 +113,7 @@ template trimZeroes(b: seq[byte], pt, ptlen: untyped) = ptlen -= 1 proc random*[T: RsaKP](t: typedesc[T], bits = DefaultKeySize, - pubexp = DefaultPublicExponent): T = + pubexp = DefaultPublicExponent): RsaResult[T] = ## Generate new random RSA private key using BearSSL's HMAC-SHA256-DRBG ## algorithm. ## @@ -121,7 +126,8 @@ proc random*[T: RsaKP](t: typedesc[T], bits = DefaultKeySize, var seeder = brPrngSeederSystem(nil) brHmacDrbgInit(addr rng, addr sha256Vtable, nil, 0) if seeder(addr rng.vtable) == 0: - raise newException(RsaRngError, "Could not seed RNG") + return err(RsaRngError) + keygen = brRsaKeygenGetDefault() let length = brRsaPrivateKeyBufferSize(bits) + @@ -131,34 +137,38 @@ proc random*[T: RsaKP](t: typedesc[T], bits = DefaultKeySize, let pko = brRsaPrivateKeyBufferSize(bits) let eko = pko + brRsaPublicKeyBufferSize(bits) - when T is RsaKeyPair: - result = new RsaKeyPair - else: - result = new RsaPrivateKey + var res: T - result.buffer = newSeq[byte](length) + when T is RsaKeyPair: + res = new T + else: + res = new RsaPrivateKey + + res.buffer = newSeq[byte](length) if keygen(addr rng.vtable, - addr result.seck, addr result.buffer[sko], - addr result.pubk, addr result.buffer[pko], + addr res.seck, addr res.buffer[sko], + addr res.pubk, addr res.buffer[pko], cuint(bits), pubexp) == 0: - raise newException(RsaGenError, "Could not create private key") + return err(RsaGenError) let compute = brRsaComputePrivexpGetDefault() - let res = compute(addr result.buffer[eko], addr result.seck, pubexp) - if res == 0: - raise newException(RsaGenError, "Could not create private key") + let computed = compute(addr res.buffer[eko], addr res.seck, pubexp) + if computed == 0: + return err(RsaGenError) - result.pexp = cast[ptr cuchar](addr result.buffer[eko]) - result.pexplen = res + res.pexp = cast[ptr cuchar](addr res.buffer[eko]) + res.pexplen = computed - trimZeroes(result.buffer, result.seck.p, result.seck.plen) - trimZeroes(result.buffer, result.seck.q, result.seck.qlen) - trimZeroes(result.buffer, result.seck.dp, result.seck.dplen) - trimZeroes(result.buffer, result.seck.dq, result.seck.dqlen) - trimZeroes(result.buffer, result.seck.iq, result.seck.iqlen) - trimZeroes(result.buffer, result.pubk.n, result.pubk.nlen) - trimZeroes(result.buffer, result.pubk.e, result.pubk.elen) - trimZeroes(result.buffer, result.pexp, result.pexplen) + trimZeroes(res.buffer, res.seck.p, res.seck.plen) + trimZeroes(res.buffer, res.seck.q, res.seck.qlen) + trimZeroes(res.buffer, res.seck.dp, res.seck.dplen) + trimZeroes(res.buffer, res.seck.dq, res.seck.dqlen) + trimZeroes(res.buffer, res.seck.iq, res.seck.iqlen) + trimZeroes(res.buffer, res.pubk.n, res.pubk.nlen) + trimZeroes(res.buffer, res.pubk.e, res.pubk.elen) + trimZeroes(res.buffer, res.pexp, res.pexplen) + + ok(res) proc copy*[T: RsaPKI](key: T): T = ## Create copy of RSA private key, public key or signature. @@ -275,14 +285,15 @@ proc clear*[T: RsaPKI|RsaKeyPair](pki: var T) = burnMem(pki.buffer) pki.buffer.setLen(0) -proc toBytes*(key: RsaPrivateKey, data: var openarray[byte]): int = +proc toBytes*(key: RsaPrivateKey, data: var openarray[byte]): RsaResult[int] = ## Serialize RSA private key ``key`` to ASN.1 DER binary form and store it ## to ``data``. ## ## Procedure returns number of bytes (octets) needed to store RSA private key, ## or `0` if private key is is incorrect. - doAssert(not isNil(key)) - if len(key.buffer) > 0: + if isNil(key): + err(RsaKeyIncorrectError) + elif len(key.buffer) > 0: var b = Asn1Buffer.init() var p = Asn1Composite.init(Asn1Tag.Sequence) p.write(0'u64) @@ -304,18 +315,22 @@ proc toBytes*(key: RsaPrivateKey, data: var openarray[byte]): int = p.finish() b.write(p) b.finish() - result = len(b) - if len(data) >= result: - copyMem(addr data[0], addr b.buffer[0], result) + var blen = len(b) + if len(data) >= blen: + copyMem(addr data[0], addr b.buffer[0], blen) + ok(blen) + else: + err(RsaKeyIncorrectError) -proc toBytes*(key: RsaPublicKey, data: var openarray[byte]): int = +proc toBytes*(key: RsaPublicKey, data: var openarray[byte]): RsaResult[int] = ## Serialize RSA public key ``key`` to ASN.1 DER binary form and store it ## to ``data``. ## ## Procedure returns number of bytes (octets) needed to store RSA public key, ## or `0` if public key is incorrect. - doAssert(not isNil(key)) - if len(key.buffer) > 0: + if isNil(key): + err(RsaKeyIncorrectError) + elif len(key.buffer) > 0: var b = Asn1Buffer.init() var p = Asn1Composite.init(Asn1Tag.Sequence) var c0 = Asn1Composite.init(Asn1Tag.Sequence) @@ -334,52 +349,64 @@ proc toBytes*(key: RsaPublicKey, data: var openarray[byte]): int = p.finish() b.write(p) b.finish() - result = len(b) - if len(data) >= result: - copyMem(addr data[0], addr b.buffer[0], result) + var blen = len(b) + if len(data) >= blen: + copyMem(addr data[0], addr b.buffer[0], blen) + ok(blen) + else: + err(RsaKeyIncorrectError) -proc toBytes*(sig: RsaSignature, data: var openarray[byte]): int = +proc toBytes*(sig: RsaSignature, data: var openarray[byte]): RSaResult[int] = ## Serialize RSA signature ``sig`` to raw binary form and store it ## to ``data``. ## ## Procedure returns number of bytes (octets) needed to store RSA public key, ## or `0` if public key is incorrect. - doAssert(not isNil(sig)) - result = len(sig.buffer) - if len(data) >= result: - copyMem(addr data[0], addr sig.buffer[0], result) + if isNil(sig): + err(RsaSignatureError) + else: + var slen = len(sig.buffer) + if len(data) >= slen: + copyMem(addr data[0], addr sig.buffer[0], slen) + ok(slen) -proc getBytes*(key: RsaPrivateKey): seq[byte] = +proc getBytes*(key: RsaPrivateKey): RsaResult[seq[byte]] = ## Serialize RSA private key ``key`` to ASN.1 DER binary form and ## return it. - doAssert(not isNil(key)) - result = newSeq[byte](4096) - let length = key.toBytes(result) + if isNil(key): + return err(RsaKeyIncorrectError) + var res = newSeq[byte](4096) + let length = ? key.toBytes(res) if length > 0: - result.setLen(length) + res.setLen(length) + ok(res) else: - raise newException(RsaKeyIncorrectError, "Incorrect private key") + err(RsaKeyIncorrectError) -proc getBytes*(key: RsaPublicKey): seq[byte] = +proc getBytes*(key: RsaPublicKey): RsaResult[seq[byte]] = ## Serialize RSA public key ``key`` to ASN.1 DER binary form and ## return it. - doAssert(not isNil(key)) - result = newSeq[byte](4096) - let length = key.toBytes(result) + if isNil(key): + return err(RsaKeyIncorrectError) + var res = newSeq[byte](4096) + let length = ? key.toBytes(res) if length > 0: - result.setLen(length) + res.setLen(length) + ok(res) else: - raise newException(RsaKeyIncorrectError, "Incorrect private key") + err(RsaKeyIncorrectError) -proc getBytes*(sig: RsaSignature): seq[byte] = +proc getBytes*(sig: RsaSignature): RsaResult[seq[byte]] = ## Serialize RSA signature ``sig`` to raw binary form and return it. - doAssert(not isNil(sig)) - result = newSeq[byte](4096) - let length = sig.toBytes(result) + if isNil(sig): + return err(RsaSignatureError) + var res = newSeq[byte](4096) + let length = ? sig.toBytes(res) if length > 0: - result.setLen(length) + res.setLen(length) + ok(res) else: - raise newException(RsaSignatureError, "Incorrect signature") + err(RsaSignatureError) proc init*(key: var RsaPrivateKey, data: openarray[byte]): Result[void, Asn1Error] = ## Initialize RSA private key ``key`` from ASN.1 DER binary representation @@ -560,29 +587,32 @@ proc init*[T: RsaPKI](sospk: var T, data: string): Result[void, Asn1Error] {.inl ## Procedure returns ``Result[void, Asn1Status]``. sospk.init(fromHex(data)) -proc init*(t: typedesc[RsaPrivateKey], data: openarray[byte]): RsaPrivateKey = +proc init*(t: typedesc[RsaPrivateKey], data: openarray[byte]): RsaResult[RsaPrivateKey] = ## Initialize RSA private key from ASN.1 DER binary representation ``data`` ## and return constructed object. - let res = result.init(data) - if res.isErr: - raise newException(RsaKeyIncorrectError, - "Incorrect private key (" & $res.error & ")") + var res: RsaPrivateKey + if res.init(data).isErr: + err(RsaKeyIncorrectError) + else: + ok(res) -proc init*(t: typedesc[RsaPublicKey], data: openarray[byte]): RsaPublicKey = +proc init*(t: typedesc[RsaPublicKey], data: openarray[byte]): RsaResult[RsaPublicKey] = ## Initialize RSA public key from ASN.1 DER binary representation ``data`` ## and return constructed object. - let res = result.init(data) - if res.isErr: - raise newException(RsaKeyIncorrectError, - "Incorrect public key (" & $res.error & ")") + var res: RsaPublicKey + if res.init(data).isErr: + err(RsaKeyIncorrectError) + else: + ok(res) -proc init*(t: typedesc[RsaSignature], data: openarray[byte]): RsaSignature = +proc init*(t: typedesc[RsaSignature], data: openarray[byte]): RsaResult[RsaSignature] = ## Initialize RSA signature from raw binary representation ``data`` and ## return constructed object. - let res = result.init(data) - if res.isErr: - raise newException(RsaKeyIncorrectError, - "Incorrect signature (" & $res.error & ")") + var res: RsaSignature + if res.init(data).isErr: + err(RsaSignatureError) + else: + ok(res) proc init*[T: RsaPKI](t: typedesc[T], data: string): T {.inline.} = ## Initialize RSA `private key`, `public key` or `signature` from hexadecimal @@ -714,15 +744,17 @@ proc `==`*(a, b: RsaPublicKey): bool = result = r1 and r2 proc sign*[T: byte|char](key: RsaPrivateKey, - message: openarray[T]): RsaSignature {.gcsafe.} = + message: openarray[T]): RsaResult[RsaSignature] {.gcsafe.} = ## Get RSA PKCS1.5 signature of data ``message`` using SHA256 and private ## key ``key``. - doAssert(not isNil(key)) + if isNil(key): + return err(RsaKeyIncorrectError) + var hc: BrHashCompatContext var hash: array[32, byte] let impl = BrRsaPkcs1SignGetDefault() - result = new RsaSignature - result.buffer = newSeq[byte]((key.seck.nBitlen + 7) shr 3) + var res = new RsaSignature + res.buffer = newSeq[byte]((key.seck.nBitlen + 7) shr 3) var kv = addr sha256Vtable kv.init(addr hc.vtable) if len(message) > 0: @@ -731,11 +763,13 @@ proc sign*[T: byte|char](key: RsaPrivateKey, kv.update(addr hc.vtable, nil, 0) kv.output(addr hc.vtable, addr hash[0]) var oid = RsaOidSha256 - let res = impl(cast[ptr cuchar](addr oid[0]), + let implRes = impl(cast[ptr cuchar](addr oid[0]), cast[ptr cuchar](addr hash[0]), len(hash), - addr key.seck, cast[ptr cuchar](addr result.buffer[0])) - if res == 0: - raise newException(RsaSignatureError, "Signature generation error") + addr key.seck, cast[ptr cuchar](addr res.buffer[0])) + if implRes == 0: + err(RsaSignatureError) + else: + ok(res) proc verify*[T: byte|char](sig: RsaSignature, message: openarray[T], pubkey: RsaPublicKey): bool {.inline.} = diff --git a/libp2p/crypto/secp.nim b/libp2p/crypto/secp.nim index d1a547564..71164035f 100644 --- a/libp2p/crypto/secp.nim +++ b/libp2p/crypto/secp.nim @@ -6,8 +6,15 @@ ## at your option. ## This file may not be copied, modified, or distributed except according to ## those terms. -import secp256k1 as s, stew/byteutils, nimcrypto/hash, nimcrypto/sha2 + +{.push raises: [Defect].} + +import secp256k1, stew/byteutils, nimcrypto/hash, nimcrypto/sha2 export sha2 +import stew/results + +export results +export secp256k1 const SkRawPrivateKeySize* = 256 div 8 @@ -18,169 +25,125 @@ const ## Size of public key in octets (bytes) type - SkPublicKey* = distinct s.SkPublicKey - SkPrivateKey* = distinct s.SkSecretKey - SkKeyPair* = distinct s.SkKeyPair - SkSignature* = distinct s.SkSignature + SkPrivateKey* = SkSecretKey - Secp256k1Error* = object of CatchableError - ## Exceptions generated by `libsecp256k1` +template pubkey*(v: SkKeyPair): SkPublicKey = SkPublicKey(SkKeyPair(v).pubkey) +template seckey*(v: SkKeyPair): SkPrivateKey = SkPrivateKey(SkKeyPair(v).seckey) -template toException(v: cstring): (ref Secp256k1Error) = - (ref Secp256k1Error)(msg: $v) - -template pubkey*(v: SkKeyPair): SkPublicKey = SkPublicKey(s.SkKeyPair(v).pubkey) -template seckey*(v: SkKeyPair): SkPrivateKey = SkPrivateKey(s.SkKeyPair(v).seckey) - -proc init*(key: var SkPrivateKey, data: openarray[byte]): bool {.raises: [Defect].} = +proc init*(key: var SkPrivateKey, data: openarray[byte]): SkResult[void] = ## Initialize Secp256k1 `private key` ``key`` from raw binary ## representation ``data``. - ## - ## Procedure returns ``true`` on success. - if (let v = SkSecretKey.fromRaw(data); v.isOk): - key = SkPrivateKey(v[]) - return true + key = ? SkSecretKey.fromRaw(data) + ok() -proc init*(key: var SkPrivateKey, data: string): bool {.raises: [Defect].} = +proc init*(key: var SkPrivateKey, data: string): SkResult[void] = ## Initialize Secp256k1 `private key` ``key`` from hexadecimal string ## representation ``data``. - ## - ## Procedure returns ``true`` on success. - try: - key = SkPrivateKey(SkSecretKey.fromHex(data).tryGet()) - return true - except Secp256k1Error: - discard + key = ? SkSecretKey.fromHex(data) + ok() -proc init*(key: var SkPublicKey, data: openarray[byte]): bool {.raises: [Defect].} = +proc init*(key: var SkPublicKey, data: openarray[byte]): SkResult[void] = ## Initialize Secp256k1 `public key` ``key`` from raw binary ## representation ``data``. - ## - ## Procedure returns ``true`` on success. - try: - key = SkPublicKey(s.SkPublicKey.fromRaw(data).tryGet()) - return true - except Secp256k1Error: - discard + key = ? SkPublicKey.fromRaw(data) + ok() -proc init*(key: var SkPublicKey, data: string): bool {.raises: [Defect].} = +proc init*(key: var SkPublicKey, data: string): SkResult[void] = ## Initialize Secp256k1 `public key` ``key`` from hexadecimal string ## representation ``data``. - ## - ## Procedure returns ``true`` on success. - try: - key = SkPublicKey(s.SkPublicKey.fromHex(data).tryGet()) - return true - except Secp256k1Error: - discard + key = ? SkPublicKey.fromHex(data) + ok() -proc init*(sig: var SkSignature, data: openarray[byte]): bool {.raises: [Defect].} = +proc init*(sig: var SkSignature, data: openarray[byte]): SkResult[void] = ## Initialize Secp256k1 `signature` ``sig`` from raw binary ## representation ``data``. - ## - ## Procedure returns ``true`` on success. - try: - sig = SkSignature(s.SkSignature.fromDer(data).tryGet()) - return true - except Secp256k1Error: - discard + sig = ? SkSignature.fromDer(data) + ok() -proc init*(sig: var SkSignature, data: string): bool {.raises: [Defect].} = +proc init*(sig: var SkSignature, data: string): SkResult[void] = ## Initialize Secp256k1 `signature` ``sig`` from hexadecimal string ## representation ``data``. - ## - ## Procedure returns ``true`` on success. # TODO DER vs raw here is fishy var buffer: seq[byte] try: buffer = hexToSeqByte(data) except ValueError: - return false - result = init(sig, buffer) + return err("Hex to bytes failed") + init(sig, buffer) -proc init*(t: typedesc[SkPrivateKey], - data: openarray[byte]): SkPrivateKey {.raises: [Defect, Secp256k1Error].} = +proc init*(t: typedesc[SkPrivateKey], data: openarray[byte]): SkResult[SkPrivateKey] = ## Initialize Secp256k1 `private key` from raw binary ## representation ``data``. ## ## Procedure returns `private key` on success. - SkPrivateKey(s.SkSecretKey.fromRaw(data).tryGet()) + SkSecretKey.fromRaw(data) -proc init*(t: typedesc[SkPrivateKey], - data: string): SkPrivateKey {.raises: [Defect, Secp256k1Error].} = +proc init*(t: typedesc[SkPrivateKey], data: string): SkResult[SkPrivateKey] = ## Initialize Secp256k1 `private key` from hexadecimal string ## representation ``data``. ## ## Procedure returns `private key` on success. - s.SkSecretKey.fromHex(data).tryGet() + SkSecretKey.fromHex(data) -proc init*(t: typedesc[SkPublicKey], - data: openarray[byte]): SkPublicKey {.raises: [Defect, Secp256k1Error].} = +proc init*(t: typedesc[SkPublicKey], data: openarray[byte]): SkResult[SkPublicKey] = ## Initialize Secp256k1 `public key` from raw binary ## representation ``data``. ## ## Procedure returns `public key` on success. - if not init(result, data): - raise newException(Secp256k1Error, "Incorrect binary form") + var key: SkPublicKey + key.init(data) and ok(key) -proc init*(t: typedesc[SkPublicKey], - data: string): SkPublicKey {.raises: [Defect, Secp256k1Error].} = +proc init*(t: typedesc[SkPublicKey], data: string): SkResult[SkPublicKey] = ## Initialize Secp256k1 `public key` from hexadecimal string ## representation ``data``. ## ## Procedure returns `public key` on success. - if not init(result, data): - raise newException(Secp256k1Error, "Incorrect binary form") + var key: SkPublicKey + key.init(data) and ok(key) -proc init*(t: typedesc[SkSignature], - data: openarray[byte]): SkSignature {.raises: [Defect, Secp256k1Error].} = +proc init*(t: typedesc[SkSignature], data: openarray[byte]): SkResult[SkSignature] = ## Initialize Secp256k1 `signature` from raw binary ## representation ``data``. ## ## Procedure returns `signature` on success. - if not init(result, data): - raise newException(Secp256k1Error, "Incorrect binary form") + var sig: SkSignature + sig.init(data) and ok(sig) -proc init*(t: typedesc[SkSignature], - data: string): SkSignature {.raises: [Defect, Secp256k1Error].} = +proc init*(t: typedesc[SkSignature], data: string): SkResult[SkSignature] = ## Initialize Secp256k1 `signature` from hexadecimal string ## representation ``data``. ## ## Procedure returns `signature` on success. - if not init(result, data): - raise newException(Secp256k1Error, "Incorrect binary form") + var sig: SkSignature + sig.init(data) and ok(sig) -proc getKey*(key: SkPrivateKey): SkPublicKey {.raises: [Defect, Secp256k1Error].} = +proc getKey*(key: SkPrivateKey): SkResult[SkPublicKey] = ## Calculate and return Secp256k1 `public key` from `private key` ``key``. - SkPublicKey(s.SkSecretKey(key).toPublicKey().tryGet()) + key.toPublicKey() -proc random*(t: typedesc[SkPrivateKey]): SkPrivateKey = - ## Generates new random private key. - SkPrivateKey(s.SkSecretKey.random().tryGet()) - -proc random*(t: typedesc[SkKeyPair]): SkKeyPair {.inline.} = - ## Generates new random key pair. - SkKeyPair(s.SkKeyPair.random().tryGet()) - -proc toBytes*(key: SkPrivateKey, data: var openarray[byte]): int = +proc toBytes*(key: SkPrivateKey, data: var openarray[byte]): SkResult[int] = ## Serialize Secp256k1 `private key` ``key`` to raw binary form and store it ## to ``data``. ## ## Procedure returns number of bytes (octets) needed to store ## Secp256k1 private key. - result = SkRawPrivateKeySize if len(data) >= SkRawPrivateKeySize: - data[0..= SkRawPublicKeySize: - data[0..= 0: + if MultiHash.decode(data, mh).isOk: vb.writeSeq(data) result = true except: @@ -151,7 +151,7 @@ proc p2pBtS(vb: var VBuffer, s: var string): bool = var address = newSeq[byte]() if vb.readSeq(address) > 0: var mh: MultiHash - if MultiHash.decode(address, mh) >= 0: + if MultiHash.decode(address, mh).isOk: s = Base58.encode(address) result = true @@ -160,7 +160,7 @@ proc p2pVB(vb: var VBuffer): bool = var address = newSeq[byte]() if vb.readSeq(address) > 0: var mh: MultiHash - if MultiHash.decode(address, mh) >= 0: + if MultiHash.decode(address, mh).isOk: result = true proc onionStB(s: string, vb: var VBuffer): bool = @@ -426,12 +426,12 @@ const proc trimRight(s: string, ch: char): string = ## Consume trailing characters ``ch`` from string ``s`` and return result. var m = 0 - for i in countdown(len(s) - 1, 0): + for i in countdown(s.high, 0): if s[i] == ch: inc(m) else: break - result = s[0..(len(s) - 1 - m)] + result = s[0..(s.high - m)] proc shcopy*(m1: var MultiAddress, m2: MultiAddress) = shallowCopy(m1.data.buffer, m2.data.buffer) diff --git a/libp2p/multibase.nim b/libp2p/multibase.nim index fb7117562..6fc888673 100644 --- a/libp2p/multibase.nim +++ b/libp2p/multibase.nim @@ -392,7 +392,7 @@ proc encode*(mbtype: typedesc[MultiBase], encoding: string, if isNil(mb.encr) or isNil(mb.encl): return MultibaseStatus.NotSupported if len(outbytes) > 1: - result = mb.encr(inbytes, outbytes.toOpenArray(1, len(outbytes) - 1), + result = mb.encr(inbytes, outbytes.toOpenArray(1, outbytes.high), outlen) if result == MultiBaseStatus.Overrun: outlen += 1 @@ -452,7 +452,7 @@ proc encode*(mbtype: typedesc[MultiBase], encoding: string, if length > 0: buffer = newString(mb.encl(length) + 1) var outlen = 0 - let res = mb.encr(inbytes, buffer.toOpenArray(1, len(buffer) - 1), outlen) + let res = mb.encr(inbytes, buffer.toOpenArray(1, buffer.high), outlen) if res != MultiBaseStatus.Success: raise newException(MultiBaseError, "Encoding error [" & $res & "]") buffer.setLen(outlen + 1) diff --git a/libp2p/multicodec.nim b/libp2p/multicodec.nim index bace64863..33ef889bb 100644 --- a/libp2p/multicodec.nim +++ b/libp2p/multicodec.nim @@ -8,8 +8,13 @@ ## those terms. ## This module implements MultiCodec. + +{.push raises: [Defect].} + import tables, hashes import varint, vbuffer +import stew/results +export results {.deadCodeElim: on.} @@ -230,7 +235,8 @@ const MultiCodecList = [ type MultiCodec* = distinct int - MultiCodecError* = object of CatchableError + MultiCodecError* = enum + MultiCodecNotSupported const InvalidMultiCodec* = MultiCodec(-1) @@ -251,37 +257,32 @@ const proc multiCodec*(name: string): MultiCodec {.compileTime.} = ## Generate MultiCodec from string ``name`` at compile time. - var code = NameCodecs.getOrDefault(name, -1) - if code == -1: - raise newException(MultiCodecError, - "MultiCodec `" & name & "` not supported!") - result = MultiCodec(code) + let code = NameCodecs.getOrDefault(name, -1) + doAssert(code != -1) + MultiCodec(code) proc multiCodec*(code: int): MultiCodec {.compileTime.} = ## Generate MultiCodec from integer ``code`` at compile time. - var name = CodeCodecs.getOrDefault(code, "") - if name == "": - raise newException(MultiCodecError, - "MultiCodec with code " & $code & " not supported!") - result = MultiCodec(code) + let name = CodeCodecs.getOrDefault(code, "") + doAssert(name != "") + MultiCodec(code) proc `$`*(mc: MultiCodec): string = ## Returns string representation of MultiCodec ``mc``. - result = CodeCodecs.getOrDefault(int(mc), "") - if result == "": - raise newException(MultiCodecError, - "MultiCodec with code " & $int(mc) & " not supported!") + let name = CodeCodecs.getOrDefault(int(mc), "") + doAssert(name != "") + name proc `==`*(mc: MultiCodec, name: string): bool {.inline.} = ## Compares MultiCodec ``mc`` with string ``name``. - var mcname = CodeCodecs.getOrDefault(int(mc), "") + let mcname = CodeCodecs.getOrDefault(int(mc), "") if mcname == "": return false result = (mcname == name) proc `==`*(mc: MultiCodec, code: int): bool {.inline.} = ## Compares MultiCodec ``mc`` with integer ``code``. - result = (int(mc) == code) + (int(mc) == code) proc `==`*(a, b: MultiCodec): bool = ## Returns ``true`` if MultiCodecs ``a`` and ``b`` are equal. @@ -293,13 +294,13 @@ proc `!=`*(a, b: MultiCodec): bool = proc hash*(m: MultiCodec): Hash {.inline.} = ## Hash procedure for tables. - result = hash(int(m)) + hash(int(m)) proc codec*(mt: typedesc[MultiCodec], name: string): MultiCodec {.inline.} = ## Return MultiCodec from string representation ``name``. ## If ``name`` is not valid multicodec name, then ``InvalidMultiCodec`` will ## be returned. - result = MultiCodec(NameCodecs.getOrDefault(name, -1)) + MultiCodec(NameCodecs.getOrDefault(name, -1)) proc codec*(mt: typedesc[MultiCodec], code: int): MultiCodec {.inline.} = ## Return MultiCodec from integer representation ``code``. @@ -307,9 +308,9 @@ proc codec*(mt: typedesc[MultiCodec], code: int): MultiCodec {.inline.} = ## be returned. let res = CodeCodecs.getOrDefault(code, "") if res == "": - result = InvalidMultiCodec + InvalidMultiCodec else: - result = MultiCodec(code) + MultiCodec(code) proc write*(vb: var VBuffer, mc: MultiCodec) {.inline.} = ## Write MultiCodec to buffer ``vb``. diff --git a/libp2p/multihash.nim b/libp2p/multihash.nim index df69167b3..a0845a6bf 100644 --- a/libp2p/multihash.nim +++ b/libp2p/multihash.nim @@ -20,19 +20,29 @@ ## Hashes which are not yet supported ## 1. SKEIN ## 2. MURMUR + +{.push raises: [Defect].} + import tables import nimcrypto/[sha, sha2, keccak, blake2, hash, utils] import varint, vbuffer, multicodec, multibase import stew/base58 +import stew/results +export results # This is workaround for Nim `import` bug. export sha, sha2, keccak, blake2, hash, utils const MaxHashSize* = 128 + ErrIncorrectName = "Incorrect hash name" + ErrNotSupported = "Hash not supported" + ErrWrongDigestSize = "Incorrect digest size" + ErrDecodeError = "Decoding error from bytes" + ErrParseError = "Parse error fromHex" type MHashCoderProc* = proc(data: openarray[byte], - output: var openarray[byte]) {.nimcall, gcsafe.} + output: var openarray[byte]) {.nimcall, gcsafe, raises: [Defect].} MHash* = object mcodec*: MultiCodec size*: int @@ -44,7 +54,7 @@ type size*: int dpos*: int - MultiHashError* = object of CatchableError + MhResult*[T] = Result[T, cstring] proc identhash(data: openarray[byte], output: var openarray[byte]) = if len(output) > 0: @@ -345,78 +355,87 @@ proc digestImplWithoutHash(hash: MHash, data: openarray[byte]): MultiHash = result.data.finish() proc digest*(mhtype: typedesc[MultiHash], hashname: string, - data: openarray[byte]): MultiHash {.inline.} = + data: openarray[byte]): MhResult[MultiHash] {.inline.} = ## Perform digest calculation using hash algorithm with name ``hashname`` on ## data array ``data``. let mc = MultiCodec.codec(hashname) if mc == InvalidMultiCodec: - raise newException(MultihashError, "Incorrect hash name") - let hash = CodeHashes.getOrDefault(mc) - if isNil(hash.coder): - raise newException(MultihashError, "Hash not supported") - result = digestImplWithHash(hash, data) + err(ErrIncorrectName) + else: + let hash = CodeHashes.getOrDefault(mc) + if isNil(hash.coder): + err(ErrNotSupported) + else: + ok(digestImplWithHash(hash, data)) proc digest*(mhtype: typedesc[MultiHash], hashcode: int, - data: openarray[byte]): MultiHash {.inline.} = + data: openarray[byte]): MhResult[MultiHash] {.inline.} = ## Perform digest calculation using hash algorithm with code ``hashcode`` on ## data array ``data``. let hash = CodeHashes.getOrDefault(hashcode) if isNil(hash.coder): - raise newException(MultihashError, "Hash not supported") - result = digestImplWithHash(hash, data) + err(ErrNotSupported) + else: + ok(digestImplWithHash(hash, data)) proc init*[T](mhtype: typedesc[MultiHash], hashname: string, - mdigest: MDigest[T]): MultiHash {.inline.} = + mdigest: MDigest[T]): MhResult[MultiHash] {.inline.} = ## Create MultiHash from nimcrypto's `MDigest` object and hash algorithm name ## ``hashname``. let mc = MultiCodec.codec(hashname) if mc == InvalidMultiCodec: - raise newException(MultihashError, "Incorrect hash name") - let hash = CodeHashes.getOrDefault(mc) - if isNil(hash.coder): - raise newException(MultihashError, "Hash not supported") - if hash.size != len(mdigest.data): - raise newException(MultiHashError, "Incorrect MDigest[T] size") - result = digestImplWithoutHash(hash, mdigest.data) + err(ErrIncorrectName) + else: + let hash = CodeHashes.getOrDefault(mc) + if isNil(hash.coder): + err(ErrNotSupported) + elif hash.size != len(mdigest.data): + err(ErrWrongDigestSize) + else: + ok(digestImplWithoutHash(hash, mdigest.data)) proc init*[T](mhtype: typedesc[MultiHash], hashcode: MultiCodec, - mdigest: MDigest[T]): MultiHash {.inline.} = + mdigest: MDigest[T]): MhResult[MultiHash] {.inline.} = ## Create MultiHash from nimcrypto's `MDigest` and hash algorithm code ## ``hashcode``. let hash = CodeHashes.getOrDefault(hashcode) if isNil(hash.coder): - raise newException(MultihashError, "Hash not supported") - if (hash.size != 0) and (hash.size != len(mdigest.data)): - raise newException(MultiHashError, "Incorrect MDigest[T] size") - result = digestImplWithoutHash(hash, mdigest.data) + err(ErrNotSupported) + elif (hash.size != 0) and (hash.size != len(mdigest.data)): + err(ErrWrongDigestSize) + else: + ok(digestImplWithoutHash(hash, mdigest.data)) proc init*(mhtype: typedesc[MultiHash], hashname: string, - bdigest: openarray[byte]): MultiHash {.inline.} = + bdigest: openarray[byte]): MhResult[MultiHash] {.inline.} = ## Create MultiHash from array of bytes ``bdigest`` and hash algorithm code ## ``hashcode``. let mc = MultiCodec.codec(hashname) if mc == InvalidMultiCodec: - raise newException(MultihashError, "Incorrect hash name") - let hash = CodeHashes.getOrDefault(mc) - if isNil(hash.coder): - raise newException(MultihashError, "Hash not supported") - if (hash.size != 0) and (hash.size != len(bdigest)): - raise newException(MultiHashError, "Incorrect bdigest size") - result = digestImplWithoutHash(hash, bdigest) + err(ErrIncorrectName) + else: + let hash = CodeHashes.getOrDefault(mc) + if isNil(hash.coder): + err(ErrNotSupported) + elif (hash.size != 0) and (hash.size != len(bdigest)): + err(ErrWrongDigestSize) + else: + ok(digestImplWithoutHash(hash, bdigest)) proc init*(mhtype: typedesc[MultiHash], hashcode: MultiCodec, - bdigest: openarray[byte]): MultiHash {.inline.} = + bdigest: openarray[byte]): MhResult[MultiHash] {.inline.} = ## Create MultiHash from array of bytes ``bdigest`` and hash algorithm code ## ``hashcode``. let hash = CodeHashes.getOrDefault(hashcode) if isNil(hash.coder): - raise newException(MultihashError, "Hash not supported") - if (hash.size != 0) and (hash.size != len(bdigest)): - raise newException(MultiHashError, "Incorrect bdigest size") - result = digestImplWithoutHash(hash, bdigest) + err(ErrNotSupported) + elif (hash.size != 0) and (hash.size != len(bdigest)): + err(ErrWrongDigestSize) + else: + ok(digestImplWithoutHash(hash, bdigest)) proc decode*(mhtype: typedesc[MultiHash], data: openarray[byte], - mhash: var MultiHash): int = + mhash: var MultiHash): MhResult[int] = ## Decode MultiHash value from array of bytes ``data``. ## ## On success decoded MultiHash will be stored into ``mhash`` and number of @@ -426,31 +445,39 @@ proc decode*(mhtype: typedesc[MultiHash], data: openarray[byte], var code, size: uint64 var res, dpos: int if len(data) < 2: - return -1 + return err(ErrDecodeError) + var vb = initVBuffer(data) if vb.isEmpty(): - return -1 + return err(ErrDecodeError) + res = vb.readVarint(code) if res == -1: - return -1 + return err(ErrDecodeError) + dpos += res res = vb.readVarint(size) if res == -1: - return -1 + return err(ErrDecodeError) + dpos += res if size > 0x7FFF_FFFF'u64: - return -1 + return err(ErrDecodeError) + let hash = CodeHashes.getOrDefault(MultiCodec(code)) if isNil(hash.coder): - return -1 + return err(ErrDecodeError) + if (hash.size != 0) and (hash.size != int(size)): - return -1 + return err(ErrDecodeError) + if not vb.isEnough(int(size)): - return -1 - mhash = MultiHash.init(MultiCodec(code), + return err(ErrDecodeError) + + mhash = ? MultiHash.init(MultiCodec(code), vb.buffer.toOpenArray(vb.offset, vb.offset + int(size) - 1)) - result = vb.offset + int(size) + ok(vb.offset + int(size)) proc validate*(mhtype: typedesc[MultiHash], data: openarray[byte]): bool = ## Returns ``true`` if array of bytes ``data`` has correct MultiHash inside. @@ -458,7 +485,7 @@ proc validate*(mhtype: typedesc[MultiHash], data: openarray[byte]): bool = var res: VarintStatus if len(data) < 2: return false - let last = len(data) - 1 + let last = data.high var offset = 0 var length = 0 res = LP.getUVarint(data.toOpenArray(offset, last), length, code) @@ -483,15 +510,20 @@ proc validate*(mhtype: typedesc[MultiHash], data: openarray[byte]): bool = result = true proc init*(mhtype: typedesc[MultiHash], - data: openarray[byte]): MultiHash {.inline.} = + data: openarray[byte]): MhResult[MultiHash] {.inline.} = ## Create MultiHash from bytes array ``data``. - if MultiHash.decode(data, result) == -1: - raise newException(MultihashError, "Incorrect MultiHash binary format") + var hash: MultiHash + discard ? MultiHash.decode(data, hash) + ok(hash) -proc init*(mhtype: typedesc[MultiHash], data: string): MultiHash {.inline.} = +proc init*(mhtype: typedesc[MultiHash], data: string): MhResult[MultiHash] {.inline.} = ## Create MultiHash from hexadecimal string representation ``data``. - if MultiHash.decode(fromHex(data), result) == -1: - raise newException(MultihashError, "Incorrect MultiHash binary format") + var hash: MultiHash + try: + discard ? MultiHash.decode(fromHex(data), hash) + ok(hash) + except ValueError: + err(ErrParseError) proc init58*(mhtype: typedesc[MultiHash], data: string): MultiHash {.inline.} = @@ -518,7 +550,7 @@ proc `==`*[T](mh: MultiHash, mdigest: MDigest[T]): bool = if len(mdigest.data) != mh.size: return false result = cmp(mh.data.buffer.toOpenArray(mh.dpos, mh.dpos + mh.size - 1), - mdigest.data.toOpenArray(0, len(mdigest.data) - 1)) + mdigest.data.toOpenArray(0, mdigest.data.high)) proc `==`*[T](mdigest: MDigest[T], mh: MultiHash): bool {.inline.} = ## Compares MultiHash with nimcrypto's MDigest[T], returns ``true`` if diff --git a/libp2p/peer.nim b/libp2p/peer.nim index 4f49983df..a8d90af87 100644 --- a/libp2p/peer.nim +++ b/libp2p/peer.nim @@ -91,7 +91,7 @@ proc hasPublicKey*(pid: PeerID): bool = ## Returns ``true`` if ``pid`` is small enough to hold public key inside. if len(pid.data) > 0: var mh: MultiHash - if MultiHash.decode(pid.data, mh) > 0: + if MultiHash.decode(pid.data, mh).isOk: if mh.mcodec == multiCodec("identity"): result = true @@ -102,7 +102,7 @@ proc extractPublicKey*(pid: PeerID, pubkey: var PublicKey): bool = ## Returns ``false`` otherwise. var mh: MultiHash if len(pid.data) > 0: - if MultiHash.decode(pid.data, mh) > 0: + if MultiHash.decode(pid.data, mh).isOk: if mh.mcodec == multiCodec("identity"): let length = len(mh.data.buffer) result = pubkey.init(mh.data.buffer.toOpenArray(mh.dpos, length - 1)) @@ -117,7 +117,7 @@ proc `$`*(pid: PeerID): string = for i in 0..<2: result.add(spid[i]) result.add("*") - for i in (len(spid) - 6)..(len(spid) - 1): + for i in (len(spid) - 6)..spid.high: result.add(spid[i]) proc init*(pid: var PeerID, data: openarray[byte]): bool = @@ -155,17 +155,17 @@ proc init*(t: typedesc[PeerID], data: string): PeerID {.inline.} = proc init*(t: typedesc[PeerID], pubkey: PublicKey): PeerID = ## Create new peer id from public key ``pubkey``. - var pubraw = pubkey.getBytes() + var pubraw = pubkey.getBytes().tryGet() var mh: MultiHash if len(pubraw) <= maxInlineKeyLength: - mh = MultiHash.digest("identity", pubraw) + mh = MultiHash.digest("identity", pubraw).tryGet() else: - mh = MultiHash.digest("sha2-256", pubraw) + mh = MultiHash.digest("sha2-256", pubraw).tryGet() result.data = mh.data.buffer proc init*(t: typedesc[PeerID], seckey: PrivateKey): PeerID {.inline.} = ## Create new peer id from private key ``seckey``. - result = PeerID.init(seckey.getKey()) + result = PeerID.init(seckey.getKey().tryGet()) proc match*(pid: PeerID, pubkey: PublicKey): bool {.inline.} = ## Returns ``true`` if ``pid`` matches public key ``pubkey``. diff --git a/libp2p/peerinfo.nim b/libp2p/peerinfo.nim index bad3f4466..2868ed0d5 100644 --- a/libp2p/peerinfo.nim +++ b/libp2p/peerinfo.nim @@ -118,4 +118,4 @@ proc publicKey*(p: PeerInfo): Option[PublicKey] {.inline.} = elif p.key.isSome: result = p.key else: - result = some(p.privateKey.getKey()) + result = some(p.privateKey.getKey().tryGet()) diff --git a/libp2p/protocols/identify.nim b/libp2p/protocols/identify.nim index d4a85e18c..60e1f36ec 100644 --- a/libp2p/protocols/identify.nim +++ b/libp2p/protocols/identify.nim @@ -47,7 +47,7 @@ type proc encodeMsg*(peerInfo: PeerInfo, observedAddrs: Multiaddress): ProtoBuffer = result = initProtoBuffer() - result.write(initProtoField(1, peerInfo.publicKey.get().getBytes())) + result.write(initProtoField(1, peerInfo.publicKey.get().getBytes().tryGet())) for ma in peerInfo.addrs: result.write(initProtoField(2, ma.data.buffer)) diff --git a/libp2p/protocols/pubsub/rpc/message.nim b/libp2p/protocols/pubsub/rpc/message.nim index 11109eab0..61ef194ac 100644 --- a/libp2p/protocols/pubsub/rpc/message.nim +++ b/libp2p/protocols/pubsub/rpc/message.nim @@ -33,7 +33,7 @@ proc sign*(msg: Message, p: PeerInfo): Message {.gcsafe.} = if buff.buffer.len > 0: result = msg result.signature = p.privateKey. - sign(cast[seq[byte]](PubSubPrefix) & buff.buffer). + sign(cast[seq[byte]](PubSubPrefix) & buff.buffer).tryGet(). getBytes() proc verify*(m: Message, p: PeerInfo): bool = @@ -57,7 +57,7 @@ proc newMessage*(p: PeerInfo, sign: bool = true): Message {.gcsafe.} = var seqno: seq[byte] = newSeq[byte](20) if p.publicKey.isSome and randomBytes(addr seqno[0], 20) > 0: - var key: seq[byte] = p.publicKey.get().getBytes() + var key: seq[byte] = p.publicKey.get().getBytes().tryGet() result = Message(fromPeer: p.peerId.getBytes(), data: data, diff --git a/libp2p/protocols/secure/noise.nim b/libp2p/protocols/secure/noise.nim index 46d3d69f0..cdbad727b 100644 --- a/libp2p/protocols/secure/noise.nim +++ b/libp2p/protocols/secure/noise.nim @@ -470,7 +470,8 @@ method handshake*(p: Noise, conn: Connection, initiator: bool = false): Future[S # https://github.com/libp2p/specs/tree/master/noise#libp2p-data-in-handshake-messages let - signedPayload = p.localPrivateKey.sign(PayloadString.toBytes & p.noisePublicKey.getBytes) + signedPayload = p.localPrivateKey.sign( + PayloadString.toBytes & p.noisePublicKey.getBytes).tryGet() var libp2pProof = initProtoBuffer() @@ -532,7 +533,7 @@ proc newNoise*(privateKey: PrivateKey; outgoing: bool = true; commonPrologue: se new result result.outgoing = outgoing result.localPrivateKey = privateKey - result.localPublicKey = privateKey.getKey() + result.localPublicKey = privateKey.getKey().tryGet() discard randomBytes(result.noisePrivateKey) result.noisePublicKey = result.noisePrivateKey.public() result.commonPrologue = commonPrologue diff --git a/libp2p/protocols/secure/secio.nim b/libp2p/protocols/secure/secio.nim index da5735346..d5fa7421a 100644 --- a/libp2p/protocols/secure/secio.nim +++ b/libp2p/protocols/secure/secio.nim @@ -166,7 +166,7 @@ proc macCheckAndDecode(sconn: SecioConn, data: var seq[byte]): bool = if not equalMem(addr data[mark], addr macData[0], macsize): trace "Invalid MAC", calculated = toHex(macData.toOpenArray(0, macsize - 1)), - stored = toHex(data.toOpenArray(mark, len(data) - 1)) + stored = toHex(data.toOpenArray(mark, data.high)) return false sconn.readerCoder.decrypt(data.toOpenArray(0, mark - 1), @@ -303,7 +303,7 @@ method handshake*(s: Secio, conn: Connection, initiator: bool = false): Future[S remoteHashes: string remotePeerId: PeerID localPeerId: PeerID - localBytesPubkey = s.localPublicKey.getBytes() + localBytesPubkey = s.localPublicKey.getBytes().tryGet() if randomBytes(localNonce) != SecioNonceSize: raise (ref SecioError)(msg: "Could not generate random data") @@ -341,7 +341,7 @@ method handshake*(s: Secio, conn: Connection, initiator: bool = false): Future[S # TODO: PeerID check against supplied PeerID let order = getOrder(remoteBytesPubkey, localNonce, localBytesPubkey, - remoteNonce) + remoteNonce).tryGet() trace "Remote proposal", schemes = remoteExchanges, ciphers = remoteCiphers, hashes = remoteHashes, pubkey = remoteBytesPubkey.shortLog, order = order, @@ -357,11 +357,11 @@ method handshake*(s: Secio, conn: Connection, initiator: bool = false): Future[S trace "Encryption scheme selected", scheme = scheme, cipher = cipher, hash = hash - var ekeypair = ephemeral(scheme) + var ekeypair = ephemeral(scheme).tryGet() # We need EC public key in raw binary form - var epubkey = ekeypair.pubkey.eckey.getRawBytes() + var epubkey = ekeypair.pubkey.eckey.getRawBytes().tryGet() var localCorpus = request[4..^1] & answer & epubkey - var signature = s.localPrivateKey.sign(localCorpus) + var signature = s.localPrivateKey.sign(localCorpus).tryGet() var localExchange = createExchange(epubkey, signature.getBytes()) var remoteExchange = await transactMessage(conn, localExchange) @@ -430,5 +430,5 @@ method init(s: Secio) {.gcsafe.} = proc newSecio*(localPrivateKey: PrivateKey): Secio = new result result.localPrivateKey = localPrivateKey - result.localPublicKey = localPrivateKey.getKey() + result.localPublicKey = localPrivateKey.getKey().tryGet() result.init() diff --git a/libp2p/standard_setup.nim b/libp2p/standard_setup.nim index cd0328b36..2709ad3d7 100644 --- a/libp2p/standard_setup.nim +++ b/libp2p/standard_setup.nim @@ -31,7 +31,7 @@ proc newStandardSwitch*(privKey = none(PrivateKey), result = newMplex(conn) let - seckey = privKey.get(otherwise = PrivateKey.random(ECDSA)) + seckey = privKey.get(otherwise = PrivateKey.random(ECDSA).tryGet()) peerInfo = PeerInfo.init(seckey, [address]) mplexProvider = newMuxerProvider(createMplex, MplexCodec) transports = @[Transport(newTransport(TcpTransport, transportFlags))] diff --git a/libp2p/vbuffer.nim b/libp2p/vbuffer.nim index 585a12a13..1ee9b521a 100644 --- a/libp2p/vbuffer.nim +++ b/libp2p/vbuffer.nim @@ -24,9 +24,15 @@ template isEnough*(vb: VBuffer, length: int): bool = ## Returns ``true`` if buffer ``vb`` holds at least ``length`` bytes. len(vb.buffer) - vb.offset - length >= 0 +proc high*(vb: VBuffer): int = + ## Returns number of bytes left in buffer ``vb``. + result = vb.buffer.high - vb.offset + doAssert(result >= 0) + proc len*(vb: VBuffer): int = ## Returns number of bytes left in buffer ``vb``. result = len(vb.buffer) - vb.offset + doAssert(result >= 0) proc isLiteral[T](s: seq[T]): bool {.inline.} = type @@ -58,7 +64,7 @@ proc writePBVarint*(vb: var VBuffer, value: PBSomeUVarint) = var length = 0 var v = value and cast[type(value)](0xFFFF_FFFF_FFFF_FFFF) vb.buffer.setLen(len(vb.buffer) + vsizeof(v)) - let res = PB.putUVarint(toOpenArray(vb.buffer, vb.offset, len(vb.buffer) - 1), + let res = PB.putUVarint(toOpenArray(vb.buffer, vb.offset, vb.buffer.high), length, v) doAssert(res == VarintStatus.Success) vb.offset += length @@ -69,7 +75,7 @@ proc writeLPVarint*(vb: var VBuffer, value: LPSomeUVarint) = # LibP2P varint supports only 63 bits. var v = value and cast[type(value)](0x7FFF_FFFF_FFFF_FFFF) vb.buffer.setLen(len(vb.buffer) + vsizeof(v)) - let res = LP.putUVarint(toOpenArray(vb.buffer, vb.offset, len(vb.buffer) - 1), + let res = LP.putUVarint(toOpenArray(vb.buffer, vb.offset, vb.buffer.high), length, v) doAssert(res == VarintStatus.Success) vb.offset += length @@ -82,7 +88,7 @@ proc writeSeq*[T: byte|char](vb: var VBuffer, value: openarray[T]) = ## varint length of the array. var length = 0 vb.buffer.setLen(len(vb.buffer) + vsizeof(uint(len(value))) + len(value)) - let res = LP.putUVarint(toOpenArray(vb.buffer, vb.offset, len(vb.buffer) - 1), + let res = LP.putUVarint(toOpenArray(vb.buffer, vb.offset, vb.buffer.high), length, uint(len(value))) doAssert(res == VarintStatus.Success) vb.offset += length @@ -113,7 +119,7 @@ proc peekVarint*(vb: var VBuffer, value: var LPSomeUVarint): int = var length = 0 if not vb.isEmpty(): let res = LP.getUVarint( - toOpenArray(vb.buffer, vb.offset, len(vb.buffer) - 1), length, value) + toOpenArray(vb.buffer, vb.offset, vb.buffer.high), length, value) if res == VarintStatus.Success: result = length @@ -129,7 +135,7 @@ proc peekSeq*[T: string|seq[byte]](vb: var VBuffer, value: var T): int = var length = 0 var size = 0'u64 if not vb.isEmpty() and - LP.getUVarint(toOpenArray(vb.buffer, vb.offset, len(vb.buffer) - 1), + LP.getUVarint(toOpenArray(vb.buffer, vb.offset, vb.buffer.high), length, size) == VarintStatus.Success: vb.offset += length result = length diff --git a/tests/pubsub/testgossipinternal.nim b/tests/pubsub/testgossipinternal.nim index cf63c3c1f..e25ae8b6c 100644 --- a/tests/pubsub/testgossipinternal.nim +++ b/tests/pubsub/testgossipinternal.nim @@ -19,7 +19,7 @@ suite "GossipSub internal": test "`rebalanceMesh` Degree Lo": proc testRun(): Future[bool] {.async.} = let gossipSub = newPubSub(TestGossipSub, - PeerInfo.init(PrivateKey.random(RSA))) + PeerInfo.init(PrivateKey.random(RSA).get())) let topic = "foobar" gossipSub.mesh[topic] = initHashSet[string]() @@ -28,7 +28,7 @@ suite "GossipSub internal": for i in 0..<15: let conn = newConnection(newBufferStream()) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(RSA)) + let peerInfo = PeerInfo.init(PrivateKey.random(RSA).get()) conn.peerInfo = peerInfo gossipSub.peers[peerInfo.id] = newPubSubPeer(peerInfo, GossipSubCodec) gossipSub.peers[peerInfo.id].conn = conn @@ -48,7 +48,7 @@ suite "GossipSub internal": test "`rebalanceMesh` Degree Hi": proc testRun(): Future[bool] {.async.} = let gossipSub = newPubSub(TestGossipSub, - PeerInfo.init(PrivateKey.random(RSA))) + PeerInfo.init(PrivateKey.random(RSA).get())) let topic = "foobar" gossipSub.gossipsub[topic] = initHashSet[string]() @@ -57,7 +57,7 @@ suite "GossipSub internal": for i in 0..<15: let conn = newConnection(newBufferStream()) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(RSA)) + let peerInfo = PeerInfo.init(PrivateKey.random(RSA).get()) conn.peerInfo = peerInfo gossipSub.peers[peerInfo.id] = newPubSubPeer(peerInfo, GossipSubCodec) gossipSub.peers[peerInfo.id].conn = conn @@ -77,7 +77,7 @@ suite "GossipSub internal": test "`replenishFanout` Degree Lo": proc testRun(): Future[bool] {.async.} = let gossipSub = newPubSub(TestGossipSub, - PeerInfo.init(PrivateKey.random(RSA))) + PeerInfo.init(PrivateKey.random(RSA).get())) proc handler(peer: PubSubPeer, msg: seq[RPCMsg]) {.async.} = discard @@ -89,7 +89,7 @@ suite "GossipSub internal": for i in 0..<15: let conn = newConnection(newBufferStream()) conns &= conn - var peerInfo = PeerInfo.init(PrivateKey.random(RSA)) + var peerInfo = PeerInfo.init(PrivateKey.random(RSA).get()) conn.peerInfo = peerInfo gossipSub.peers[peerInfo.id] = newPubSubPeer(peerInfo, GossipSubCodec) gossipSub.peers[peerInfo.id].handler = handler @@ -109,7 +109,7 @@ suite "GossipSub internal": test "`dropFanoutPeers` drop expired fanout topics": proc testRun(): Future[bool] {.async.} = let gossipSub = newPubSub(TestGossipSub, - PeerInfo.init(PrivateKey.random(RSA))) + PeerInfo.init(PrivateKey.random(RSA).get())) proc handler(peer: PubSubPeer, msg: seq[RPCMsg]) {.async.} = discard @@ -122,7 +122,7 @@ suite "GossipSub internal": for i in 0..<6: let conn = newConnection(newBufferStream()) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(RSA)) + let peerInfo = PeerInfo.init(PrivateKey.random(RSA).get()) conn.peerInfo = peerInfo gossipSub.peers[peerInfo.id] = newPubSubPeer(peerInfo, GossipSubCodec) gossipSub.peers[peerInfo.id].handler = handler @@ -143,7 +143,7 @@ suite "GossipSub internal": test "`dropFanoutPeers` leave unexpired fanout topics": proc testRun(): Future[bool] {.async.} = let gossipSub = newPubSub(TestGossipSub, - PeerInfo.init(PrivateKey.random(RSA))) + PeerInfo.init(PrivateKey.random(RSA).get())) proc handler(peer: PubSubPeer, msg: seq[RPCMsg]) {.async.} = discard @@ -159,7 +159,7 @@ suite "GossipSub internal": for i in 0..<6: let conn = newConnection(newBufferStream()) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(RSA)) + let peerInfo = PeerInfo.init(PrivateKey.random(RSA).get()) conn.peerInfo = peerInfo gossipSub.peers[peerInfo.id] = newPubSubPeer(peerInfo, GossipSubCodec) gossipSub.peers[peerInfo.id].handler = handler @@ -183,7 +183,7 @@ suite "GossipSub internal": test "`getGossipPeers` - should gather up to degree D non intersecting peers": proc testRun(): Future[bool] {.async.} = let gossipSub = newPubSub(TestGossipSub, - PeerInfo.init(PrivateKey.random(RSA))) + PeerInfo.init(PrivateKey.random(RSA).get())) proc handler(peer: PubSubPeer, msg: seq[RPCMsg]) {.async.} = discard @@ -196,7 +196,7 @@ suite "GossipSub internal": for i in 0..<30: let conn = newConnection(newBufferStream()) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(RSA)) + let peerInfo = PeerInfo.init(PrivateKey.random(RSA).get()) conn.peerInfo = peerInfo gossipSub.peers[peerInfo.id] = newPubSubPeer(peerInfo, GossipSubCodec) gossipSub.peers[peerInfo.id].handler = handler @@ -208,7 +208,7 @@ suite "GossipSub internal": for i in 0..<15: let conn = newConnection(newBufferStream()) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(RSA)) + let peerInfo = PeerInfo.init(PrivateKey.random(RSA).get()) conn.peerInfo = peerInfo gossipSub.peers[peerInfo.id] = newPubSubPeer(peerInfo, GossipSubCodec) gossipSub.peers[peerInfo.id].handler = handler @@ -234,7 +234,7 @@ suite "GossipSub internal": test "`getGossipPeers` - should not crash on missing topics in mesh": proc testRun(): Future[bool] {.async.} = let gossipSub = newPubSub(TestGossipSub, - PeerInfo.init(PrivateKey.random(RSA))) + PeerInfo.init(PrivateKey.random(RSA).get())) proc handler(peer: PubSubPeer, msg: seq[RPCMsg]) {.async.} = discard @@ -246,7 +246,7 @@ suite "GossipSub internal": for i in 0..<30: let conn = newConnection(newBufferStream()) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(RSA)) + let peerInfo = PeerInfo.init(PrivateKey.random(RSA).get()) conn.peerInfo = peerInfo gossipSub.peers[peerInfo.id] = newPubSubPeer(peerInfo, GossipSubCodec) gossipSub.peers[peerInfo.id].handler = handler @@ -268,7 +268,7 @@ suite "GossipSub internal": test "`getGossipPeers` - should not crash on missing topics in gossip": proc testRun(): Future[bool] {.async.} = let gossipSub = newPubSub(TestGossipSub, - PeerInfo.init(PrivateKey.random(RSA))) + PeerInfo.init(PrivateKey.random(RSA).get())) proc handler(peer: PubSubPeer, msg: seq[RPCMsg]) {.async.} = discard @@ -280,7 +280,7 @@ suite "GossipSub internal": for i in 0..<30: let conn = newConnection(newBufferStream()) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(RSA)) + let peerInfo = PeerInfo.init(PrivateKey.random(RSA).get()) conn.peerInfo = peerInfo gossipSub.peers[peerInfo.id] = newPubSubPeer(peerInfo, GossipSubCodec) gossipSub.peers[peerInfo.id].handler = handler @@ -302,7 +302,7 @@ suite "GossipSub internal": test "`getGossipPeers` - should not crash on missing topics in gossip": proc testRun(): Future[bool] {.async.} = let gossipSub = newPubSub(TestGossipSub, - PeerInfo.init(PrivateKey.random(RSA))) + PeerInfo.init(PrivateKey.random(RSA).get())) proc handler(peer: PubSubPeer, msg: seq[RPCMsg]) {.async.} = discard @@ -314,7 +314,7 @@ suite "GossipSub internal": for i in 0..<30: let conn = newConnection(newBufferStream()) conns &= conn - let peerInfo = PeerInfo.init(PrivateKey.random(RSA)) + let peerInfo = PeerInfo.init(PrivateKey.random(RSA).get()) conn.peerInfo = peerInfo gossipSub.peers[peerInfo.id] = newPubSubPeer(peerInfo, GossipSubCodec) gossipSub.peers[peerInfo.id].handler = handler diff --git a/tests/pubsub/testgossipsub.nim b/tests/pubsub/testgossipsub.nim index 05d5c490d..c45ceecbb 100644 --- a/tests/pubsub/testgossipsub.nim +++ b/tests/pubsub/testgossipsub.nim @@ -25,7 +25,7 @@ import utils, ../../libp2p/[errors, import ../helpers proc createGossipSub(): GossipSub = - var peerInfo = PeerInfo.init(PrivateKey.random(RSA)) + var peerInfo = PeerInfo.init(PrivateKey.random(RSA).get()) result = newPubSub(GossipSub, peerInfo) proc waitSub(sender, receiver: auto; key: string) {.async, gcsafe.} = diff --git a/tests/pubsub/testmcache.nim b/tests/pubsub/testmcache.nim index 7eec8d342..afdcba49a 100644 --- a/tests/pubsub/testmcache.nim +++ b/tests/pubsub/testmcache.nim @@ -11,7 +11,7 @@ import ../../libp2p/[peer, suite "MCache": test "put/get": var mCache = newMCache(3, 5) - var msg = Message(fromPeer: PeerID.init(PrivateKey.random(RSA)).data, + var msg = Message(fromPeer: PeerID.init(PrivateKey.random(RSA).get()).data, seqno: cast[seq[byte]]("12345")) mCache.put(msg) check mCache.get(msg.msgId).isSome and mCache.get(msg.msgId).get() == msg @@ -20,13 +20,13 @@ suite "MCache": var mCache = newMCache(3, 5) for i in 0..<3: - var msg = Message(fromPeer: PeerID.init(PrivateKey.random(RSA)).data, + var msg = Message(fromPeer: PeerID.init(PrivateKey.random(RSA).get()).data, seqno: cast[seq[byte]]("12345"), topicIDs: @["foo"]) mCache.put(msg) for i in 0..<5: - var msg = Message(fromPeer: PeerID.init(PrivateKey.random(RSA)).data, + var msg = Message(fromPeer: PeerID.init(PrivateKey.random(RSA).get()).data, seqno: cast[seq[byte]]("12345"), topicIDs: @["bar"]) mCache.put(msg) @@ -41,7 +41,7 @@ suite "MCache": var mCache = newMCache(1, 5) for i in 0..<3: - var msg = Message(fromPeer: PeerID.init(PrivateKey.random(RSA)).data, + var msg = Message(fromPeer: PeerID.init(PrivateKey.random(RSA).get()).data, seqno: cast[seq[byte]]("12345"), topicIDs: @["foo"]) mCache.put(msg) @@ -50,7 +50,7 @@ suite "MCache": check mCache.window("foo").len == 0 for i in 0..<3: - var msg = Message(fromPeer: PeerID.init(PrivateKey.random(RSA)).data, + var msg = Message(fromPeer: PeerID.init(PrivateKey.random(RSA).get()).data, seqno: cast[seq[byte]]("12345"), topicIDs: @["bar"]) mCache.put(msg) @@ -59,7 +59,7 @@ suite "MCache": check mCache.window("bar").len == 0 for i in 0..<3: - var msg = Message(fromPeer: PeerID.init(PrivateKey.random(RSA)).data, + var msg = Message(fromPeer: PeerID.init(PrivateKey.random(RSA).get()).data, seqno: cast[seq[byte]]("12345"), topicIDs: @["baz"]) mCache.put(msg) @@ -71,19 +71,19 @@ suite "MCache": var mCache = newMCache(1, 5) for i in 0..<3: - var msg = Message(fromPeer: PeerID.init(PrivateKey.random(RSA)).data, + var msg = Message(fromPeer: PeerID.init(PrivateKey.random(RSA).get()).data, seqno: cast[seq[byte]]("12345"), topicIDs: @["foo"]) mCache.put(msg) for i in 0..<3: - var msg = Message(fromPeer: PeerID.init(PrivateKey.random(RSA)).data, + var msg = Message(fromPeer: PeerID.init(PrivateKey.random(RSA).get()).data, seqno: cast[seq[byte]]("12345"), topicIDs: @["bar"]) mCache.put(msg) for i in 0..<3: - var msg = Message(fromPeer: PeerID.init(PrivateKey.random(RSA)).data, + var msg = Message(fromPeer: PeerID.init(PrivateKey.random(RSA).get()).data, seqno: cast[seq[byte]]("12345"), topicIDs: @["baz"]) mCache.put(msg) diff --git a/tests/testcid.nim b/tests/testcid.nim index d714626c2..b9df56b7c 100644 --- a/tests/testcid.nim +++ b/tests/testcid.nim @@ -38,17 +38,17 @@ suite "Content identifier CID test suite": var bmsg = cast[seq[byte]](msg) var bmmsg = cast[seq[byte]](mmsg) var cid0 = Cid.init(CIDv0, multiCodec("dag-pb"), - MultiHash.digest("sha2-256", bmsg)) + MultiHash.digest("sha2-256", bmsg).get()) var cid1 = Cid.init(CIDv1, multiCodec("dag-pb"), - MultiHash.digest("sha2-256", bmsg)) + MultiHash.digest("sha2-256", bmsg).get()) var cid2 = cid1 var cid3 = cid0 var cid4 = Cid.init(CIDv1, multiCodec("dag-cbor"), - MultiHash.digest("sha2-256", bmsg)) + MultiHash.digest("sha2-256", bmsg).get()) var cid5 = Cid.init(CIDv1, multiCodec("dag-pb"), - MultiHash.digest("sha2-256", bmmsg)) + MultiHash.digest("sha2-256", bmmsg).get()) var cid6 = Cid.init(CIDv1, multiCodec("dag-pb"), - MultiHash.digest("keccak-256", bmsg)) + MultiHash.digest("keccak-256", bmsg).get()) check: cid0 == cid1 cid1 == cid2 diff --git a/tests/testcrypto.nim b/tests/testcrypto.nim index c0e230c1a..0b61101dd 100644 --- a/tests/testcrypto.nim +++ b/tests/testcrypto.nim @@ -378,13 +378,13 @@ suite "Key interface test suite": test "Go test vectors": for i in 0.. 0 + key.toBytes(skey2).expect("bytes") > 0 check: rkey1.init(skey1).isOk rkey2.init(skey2).isOk - var rkey3 = EcPrivateKey.init(skey1) - var rkey4 = EcPrivateKey.init(skey2) + var rkey3 = EcPrivateKey.init(skey1).expect("private key") + var rkey4 = EcPrivateKey.init(skey2).expect("private key") check: rkey1 == key rkey2 == key @@ -319,14 +319,14 @@ suite "EC NIST-P256/384/521 test suite": for i in 0.. 0 + pair.pubkey.toBytes(skey2).expect("bytes") > 0 rkey1.init(skey1).isOk rkey2.init(skey2).isOk - var rkey3 = EcPublicKey.init(skey1) - var rkey4 = EcPublicKey.init(skey2) + var rkey3 = EcPublicKey.init(skey1).expect("public key") + var rkey4 = EcPublicKey.init(skey2).expect("public key") check: rkey1 == pair.pubkey rkey2 == pair.pubkey @@ -335,8 +335,8 @@ suite "EC NIST-P256/384/521 test suite": test "[secp256r1] ECDHE test": for i in 0.. 0 + key.toBytes(skey2).expect("bytes") > 0 check: rkey1.init(skey1).isOk rkey2.init(skey2).isOk - var rkey3 = EcPrivateKey.init(skey1) - var rkey4 = EcPrivateKey.init(skey2) + var rkey3 = EcPrivateKey.init(skey1).expect("private key") + var rkey4 = EcPrivateKey.init(skey2).expect("private key") check: rkey1 == key rkey2 == key @@ -426,14 +426,14 @@ suite "EC NIST-P256/384/521 test suite": for i in 0.. 0 + pair.pubkey.toBytes(skey2).expect("bytes") > 0 rkey1.init(skey1).isOk rkey2.init(skey2).isOk - var rkey3 = EcPublicKey.init(skey1) - var rkey4 = EcPublicKey.init(skey2) + var rkey3 = EcPublicKey.init(skey1).expect("public key") + var rkey4 = EcPublicKey.init(skey2).expect("public key") check: rkey1 == pair.pubkey rkey2 == pair.pubkey @@ -442,8 +442,8 @@ suite "EC NIST-P256/384/521 test suite": test "[secp384r1] ECDHE test": for i in 0.. 0 + key.toBytes(skey2).expect("bytes") > 0 check: rkey1.init(skey1).isOk rkey2.init(skey2).isOk - var rkey3 = EcPrivateKey.init(skey1) - var rkey4 = EcPrivateKey.init(skey2) + var rkey3 = EcPrivateKey.init(skey1).expect("private key") + var rkey4 = EcPrivateKey.init(skey2).expect("private key") check: rkey1 == key rkey2 == key @@ -533,14 +533,14 @@ suite "EC NIST-P256/384/521 test suite": for i in 0.. 0 + pair.pubkey.toBytes(skey2).expect("bytes") > 0 rkey1.init(skey1).isOk rkey2.init(skey2).isOk - var rkey3 = EcPublicKey.init(skey1) - var rkey4 = EcPublicKey.init(skey2) + var rkey3 = EcPublicKey.init(skey1).expect("public key") + var rkey4 = EcPublicKey.init(skey2).expect("public key") check: rkey1 == pair.pubkey rkey2 == pair.pubkey @@ -549,8 +549,8 @@ suite "EC NIST-P256/384/521 test suite": test "[secp521r1] ECDHE test": for i in 0.. 0 check: rkey1.init(skey1) == true rkey2.init(skey2) == true - var rkey3 = EdPrivateKey.init(skey1) - var rkey4 = EdPrivateKey.init(skey2) + var rkey3 = EdPrivateKey.init(skey1).expect("key/sig") + var rkey4 = EdPrivateKey.init(skey2).expect("key/sig") check: rkey1 == key rkey2 == key @@ -135,14 +135,14 @@ suite "Ed25519 test suite": for i in 0.. 0 rkey1.init(skey1) == true rkey2.init(skey2) == true - var rkey3 = EdPublicKey.init(skey1) - var rkey4 = EdPublicKey.init(skey2) + var rkey3 = EdPublicKey.init(skey1).expect("key/sig") + var rkey4 = EdPublicKey.init(skey2).expect("key/sig") check: rkey1 == pair.pubkey rkey2 == pair.pubkey @@ -156,13 +156,13 @@ suite "Ed25519 test suite": test "RFC8032 test vectors": for i in 0..<5: - var key = EdPrivateKey.init(stripSpaces(SecretKeys[i])) - var exppub = EdPublicKey.init(stripSpaces(PublicKeys[i])) + var key = EdPrivateKey.init(stripSpaces(SecretKeys[i])).expect("key/sig") + var exppub = EdPublicKey.init(stripSpaces(PublicKeys[i])).expect("key/sig") var pubkey = key.getKey() check pubkey == exppub var msg = fromHex(stripSpaces(Messages[i])) var sig = key.sign(msg) - var expsig = EdSignature.init(fromHex(stripSpaces(Signatures[i]))) + var expsig = EdSignature.init(fromHex(stripSpaces(Signatures[i]))).expect("key/sig") check sig == expsig check sig.verify(msg, pubkey) == true sig.data[32] = not(sig.data[32]) @@ -171,15 +171,15 @@ suite "Ed25519 test suite": test "Generate/Sign/Serialize/Deserialize/Verify test": var message = "message to sign" for i in 0.. 0 + var key = RsaPrivateKey.random(512).expect("random key") + var skey1 = key.getBytes().expect("bytes") + check key.toBytes(skey2).expect("bytes") > 0 check: rkey1.init(skey1).isOk() rkey2.init(skey2).isOk() - var rkey3 = RsaPrivateKey.init(skey1) - var rkey4 = RsaPrivateKey.init(skey2) + var rkey3 = RsaPrivateKey.init(skey1).expect("key initialization") + var rkey4 = RsaPrivateKey.init(skey2).expect("key initialization") check: rkey1 == key rkey2 == key @@ -291,14 +291,14 @@ suite "RSA 512/1024/2048/4096 test suite": for i in 0.. 0 + var key = RsaPrivateKey.random(1024).expect("random failed") + var skey1 = key.getBytes().expect("bytes") + check key.toBytes(skey2).expect("bytes") > 0 check: rkey1.init(skey1).isOk() rkey2.init(skey2).isOk() - var rkey3 = RsaPrivateKey.init(skey1) - var rkey4 = RsaPrivateKey.init(skey2) + var rkey3 = RsaPrivateKey.init(skey1).expect("key initialization") + var rkey4 = RsaPrivateKey.init(skey2).expect("key initialization") check: rkey1 == key rkey2 == key @@ -308,14 +308,14 @@ suite "RSA 512/1024/2048/4096 test suite": test "[rsa2048] Private key serialize/deserialize test": var rkey1, rkey2: RsaPrivateKey var skey2 = newSeq[byte](4096) - var key = RsaPrivateKey.random(2048) - var skey1 = key.getBytes() - check key.toBytes(skey2) > 0 + var key = RsaPrivateKey.random(2048).expect("random failed") + var skey1 = key.getBytes().expect("bytes") + check key.toBytes(skey2).expect("bytes") > 0 check: rkey1.init(skey1).isOk() rkey2.init(skey2).isOk() - var rkey3 = RsaPrivateKey.init(skey1) - var rkey4 = RsaPrivateKey.init(skey2) + var rkey3 = RsaPrivateKey.init(skey1).expect("key initialization") + var rkey4 = RsaPrivateKey.init(skey2).expect("key initialization") check: rkey1 == key rkey2 == key @@ -327,14 +327,14 @@ suite "RSA 512/1024/2048/4096 test suite": when defined(release): var rkey1, rkey2: RsaPrivateKey var skey2 = newSeq[byte](4096) - var key = RsaPrivateKey.random(4096) - var skey1 = key.getBytes() - check key.toBytes(skey2) > 0 + var key = RsaPrivateKey.random(4096).expect("random failed") + var skey1 = key.getBytes().expect("bytes") + check key.toBytes(skey2).expect("bytes") > 0 check: rkey1.init(skey1).isOk() rkey2.init(skey2).isOk() - var rkey3 = RsaPrivateKey.init(skey1) - var rkey4 = RsaPrivateKey.init(skey2) + var rkey3 = RsaPrivateKey.init(skey1).expect("key initialization") + var rkey4 = RsaPrivateKey.init(skey2).expect("key initialization") check: rkey1 == key rkey2 == key @@ -345,14 +345,14 @@ suite "RSA 512/1024/2048/4096 test suite": for i in 0.. 0 + pair.pubkey.toBytes(skey2).expect("bytes") > 0 rkey1.init(skey1).isOk() rkey2.init(skey2).isOk() - var rkey3 = RsaPublicKey.init(skey1) - var rkey4 = RsaPublicKey.init(skey2) + var rkey3 = RsaPublicKey.init(skey1).expect("key initialization") + var rkey4 = RsaPublicKey.init(skey2).expect("key initialization") check: rkey1 == pair.pubkey rkey2 == pair.pubkey @@ -363,14 +363,14 @@ suite "RSA 512/1024/2048/4096 test suite": for i in 0.. 0 + pair.pubkey.toBytes(skey2).expect("bytes") > 0 rkey1.init(skey1).isOk() rkey2.init(skey2).isOk() - var rkey3 = RsaPublicKey.init(skey1) - var rkey4 = RsaPublicKey.init(skey2) + var rkey3 = RsaPublicKey.init(skey1).expect("key initialization") + var rkey4 = RsaPublicKey.init(skey2).expect("key initialization") check: rkey1 == pair.pubkey rkey2 == pair.pubkey @@ -380,14 +380,14 @@ suite "RSA 512/1024/2048/4096 test suite": test "[rsa2048] Public key serialize/deserialize test": var rkey1, rkey2: RsaPublicKey var skey2 = newSeq[byte](4096) - var pair = RsaKeyPair.random(2048) - var skey1 = pair.pubkey.getBytes() + var pair = RsaKeyPair.random(2048).expect("random failed") + var skey1 = pair.pubkey.getBytes().expect("bytes") check: - pair.pubkey.toBytes(skey2) > 0 + pair.pubkey.toBytes(skey2).expect("bytes") > 0 rkey1.init(skey1).isOk() rkey2.init(skey2).isOk() - var rkey3 = RsaPublicKey.init(skey1) - var rkey4 = RsaPublicKey.init(skey2) + var rkey3 = RsaPublicKey.init(skey1).expect("key initialization") + var rkey4 = RsaPublicKey.init(skey2).expect("key initialization") check: rkey1 == pair.pubkey rkey2 == pair.pubkey @@ -398,14 +398,14 @@ suite "RSA 512/1024/2048/4096 test suite": when defined(release): var rkey1, rkey2: RsaPublicKey var skey2 = newSeq[byte](4096) - var pair = RsaKeyPair.random(4096) - var skey1 = pair.pubkey.getBytes() + var pair = RsaKeyPair.random(4096).expect("random failed") + var skey1 = pair.pubkey.getBytes().expect("bytes") check: - pair.pubkey.toBytes(skey2) > 0 + pair.pubkey.toBytes(skey2).expect("bytes") > 0 rkey1.init(skey1).isOk() rkey2.init(skey2).isOk() - var rkey3 = RsaPublicKey.init(skey1) - var rkey4 = RsaPublicKey.init(skey2) + var rkey3 = RsaPublicKey.init(skey1).expect("key initialization") + var rkey4 = RsaPublicKey.init(skey2).expect("key initialization") check: rkey1 == pair.pubkey rkey2 == pair.pubkey @@ -415,154 +415,154 @@ suite "RSA 512/1024/2048/4096 test suite": test "[rsa512] Generate/Sign/Serialize/Deserialize/Verify test": var message = "message to sign" for i in 0.. 0 + key.toBytes(skey2).expect("bytes len") > 0 check: - rkey1.init(skey1) == true - rkey2.init(skey2) == true - var rkey3 = SkPrivateKey.init(skey1) - var rkey4 = SkPrivateKey.init(skey2) + rkey1.init(skey1).isOk == true + rkey2.init(skey2).isOk == true + var rkey3 = SkPrivateKey.init(skey1).expect("private key") + var rkey4 = SkPrivateKey.init(skey2).expect("private key") check: rkey1 == key rkey2 == key @@ -41,14 +41,14 @@ suite "Secp256k1 testing suite": for i in 0.. 0 - rkey1.init(skey1) == true - rkey2.init(skey2) == true - var rkey3 = SkPublicKey.init(skey1) - var rkey4 = SkPublicKey.init(skey2) + pair.pubkey.toBytes(skey2).expect("bytes len") > 0 + rkey1.init(skey1).isOk == true + rkey2.init(skey2).isOk == true + var rkey3 = SkPublicKey.init(skey1).expect("public key") + var rkey4 = SkPublicKey.init(skey2).expect("public key") check: rkey1 == pair.pubkey rkey2 == pair.pubkey @@ -59,16 +59,16 @@ suite "Secp256k1 testing suite": test "Generate/Sign/Serialize/Deserialize/Verify test": var message = "message to sign" for i in 0..