Moved base32, 58 and 64 to stew

This commit is contained in:
Yuriy Glukhov 2019-12-13 11:42:47 +02:00 committed by zah
parent 293a219dbe
commit e0aae6d8ac
15 changed files with 16 additions and 1480 deletions

View File

@ -12,7 +12,8 @@ requires "nim > 0.19.4",
"nimcrypto >= 0.4.1", "nimcrypto >= 0.4.1",
"chronos >= 2.3.4", "chronos >= 2.3.4",
"bearssl >= 0.1.3", "bearssl >= 0.1.3",
"chronicles >= 0.7.0" "chronicles >= 0.7.0",
"stew"
proc runTest(filename: string) = proc runTest(filename: string) =
exec "nim c -r tests/" & filename exec "nim c -r tests/" & filename

View File

@ -1,285 +0,0 @@
## Nim-Libp2p
## Copyright (c) 2018 Status Research & Development GmbH
## Licensed under either of
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
## * MIT license ([LICENSE-MIT](LICENSE-MIT))
## at your option.
## This file may not be copied, modified, or distributed except according to
## those terms.
## This module implements BASE32 encoding and decoding procedures.
## This module supports RFC4648's BASE32.
type
Base32Status* {.pure.} = enum
Error,
Success,
Incorrect,
Overrun
Base32Alphabet* = object
decode*: array[128, int8]
encode*: array[32, uint8]
Base32Upper* = object
## Type to use RFC4648 alphabet in uppercase without padding
Base32Lower* = object
## Type to use RFC4648 alphabet in lowercase without padding
Base32UpperPad* = object
## Type to use RFC4648 alphabet in uppercase with padding
Base32LowerPad* = object
## Type to use RFC4648 alphabet in lowercase with padding
HexBase32Upper* = object
## Type to use RFC4648-HEX alphabet in uppercase without padding
HexBase32Lower* = object
## Type to use RFC4648-HEX alphabet in lowercase without padding
HexBase32UpperPad* = object
## Type to use RFC4648-HEX alphabet in uppercase with padding
HexBase32LowerPad* = object
## Type to use RFC4648-HEX alphabet in lowercase with padding
Base32* = Base32Upper
## By default we are using RFC4648 alphabet in uppercase without padding
Base32PadTypes* = Base32UpperPad | Base32LowerPad |
HexBase32UpperPad | HexBase32LowerPad
## All types with padding support
Base32NoPadTypes* = Base32Upper | Base32Lower | HexBase32Upper |
HexBase32Lower
## All types without padding
Base32Types* = Base32NoPadTypes | Base32PadTypes
## Supported types
Base32Error* = object of CatchableError
## Base32 specific exception type
proc newAlphabet32*(s: string): Base32Alphabet =
doAssert(len(s) == 32)
for i in 0..<len(s):
result.encode[i] = cast[uint8](s[i])
for i in 0..<len(result.decode):
result.decode[i] = -1
for i in 0..<len(result.encode):
result.decode[int(result.encode[i])] = int8(i)
const
RFCUpperCaseAlphabet* = newAlphabet32("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567")
RFCLowerCaseAlphabet* = newAlphabet32("abcdefghijklmnopqrstuvwxyz234567")
HEXUpperCaseAlphabet* = newAlphabet32("0123456789ABCDEFGHIJKLMNOPQRSTUV")
HEXLowerCaseAlphabet* = newAlphabet32("0123456789abcdefghijklmnopqrstuv")
proc encodedLength*(btype: typedesc[Base32Types], length: int): int =
## Return estimated length of BASE32 encoded value for plain length
## ``length``.
let reminder = length mod 5
when btype is Base32NoPadTypes:
result = ((length div 5) * 8) + (((reminder * 8) + 4) div 5)
else:
result = ((length div 5) * 8)
if reminder != 0:
result += 8
proc decodedLength*(btype: typedesc[Base32Types], length: int): int =
## Return estimated length of decoded value of BASE32 encoded value of length
## ``length``.
let reminder = length mod 8
result = (length div 8) * 5 + ((reminder * 5) div 8)
proc convert5to8(inbytes: openarray[byte], outbytes: var openarray[char],
length: int): int {.inline.} =
if length >= 1:
outbytes[0] = chr(inbytes[0] shr 3)
outbytes[1] = chr((inbytes[0] and 7'u8) shl 2)
result = 2
if length >= 2:
outbytes[1] = chr(cast[byte](outbytes[1]) or cast[byte](inbytes[1] shr 6))
outbytes[2] = chr((inbytes[1] shr 1) and 31'u8)
outbytes[3] = chr((inbytes[1] and 1'u8) shl 4)
result = 4
if length >= 3:
outbytes[3] = chr(cast[byte](outbytes[3]) or (inbytes[2] shr 4))
outbytes[4] = chr((inbytes[2] and 15'u8) shl 1)
result = 5
if length >= 4:
outbytes[4] = chr(cast[byte](outbytes[4]) or (inbytes[3] shr 7))
outbytes[5] = chr((inbytes[3] shr 2) and 31'u8)
outbytes[6] = chr((inbytes[3] and 3'u8) shl 3)
result = 7
if length >= 5:
outbytes[6] = chr(cast[byte](outbytes[6]) or (inbytes[4] shr 5))
outbytes[7] = chr(inbytes[4] and 31'u8)
result = 8
proc convert8to5(inbytes: openarray[byte], outbytes: var openarray[byte],
length: int): int {.inline.} =
if length >= 2:
outbytes[0] = inbytes[0] shl 3
outbytes[0] = outbytes[0] or (inbytes[1] shr 2)
result = 1
if length >= 4:
outbytes[1] = (inbytes[1] and 3'u8) shl 6
outbytes[1] = outbytes[1] or (inbytes[2] shl 1)
outbytes[1] = outbytes[1] or (inbytes[3] shr 4)
result = 2
if length >= 5:
outbytes[2] = (inbytes[3] and 15'u8) shl 4
outbytes[2] = outbytes[2] or (inbytes[4] shr 1)
result = 3
if length >= 7:
outbytes[3] = (inbytes[4] and 1'u8) shl 7
outbytes[3] = outbytes[3] or (inbytes[5] shl 2)
outbytes[3] = outbytes[3] or (inbytes[6] shr 3)
result = 4
if length >= 8:
outbytes[4] = (inbytes[6] and 7'u8) shl 5
outbytes[4] = outbytes[4] or (inbytes[7] and 31'u8)
result = 5
proc encode*(btype: typedesc[Base32Types], inbytes: openarray[byte],
outstr: var openarray[char], outlen: var int): Base32Status =
## Encode array of bytes ``inbytes`` using BASE32 encoding and store
## result to ``outstr``. On success ``Base32Status.Success`` will be returned
## and ``outlen`` will be set to number of characters stored inside of
## ``outstr``. If length of ``outstr`` is not enough then
## ``Base32Status.Overrun`` will be returned and ``outlen`` will be set to
## number of characters required.
when (btype is Base32Upper) or (btype is Base32UpperPad):
const alphabet = RFCUpperCaseAlphabet
elif (btype is Base32Lower) or (btype is Base32LowerPad):
const alphabet = RFCLowerCaseAlphabet
elif (btype is HexBase32Upper) or (btype is HexBase32UpperPad):
const alphabet = HEXUpperCaseAlphabet
elif (btype is HexBase32Lower) or (btype is HexBase32LowerPad):
const alphabet = HEXLowerCaseAlphabet
if len(inbytes) == 0:
outlen = 0
return Base32Status.Success
let length = btype.encodedLength(len(inbytes))
if length > len(outstr):
outlen = length
return Base32Status.Overrun
let reminder = len(inbytes) mod 5
let limit = len(inbytes) - reminder
var i, k: int
while i < limit:
discard convert5to8(inbytes.toOpenArray(i, i + 4),
outstr.toOpenArray(k, k + 7), 5)
for j in 0..7:
outstr[k + j] = chr(alphabet.encode[ord(outstr[k + j])])
k += 8
i += 5
if reminder != 0:
let left = convert5to8(inbytes.toOpenArray(i, i + reminder - 1),
outstr.toOpenArray(k, length - 1), reminder)
for j in 0..(left - 1):
outstr[k] = chr(alphabet.encode[ord(outstr[k])])
inc(k)
when (btype is Base32UpperPad) or (btype is Base32LowerPad) or
(btype is HexBase32UpperPad) or (btype is HexBase32LowerPad):
while k < len(outstr):
outstr[k] = '='
inc(k)
outlen = k
result = Base32Status.Success
proc encode*(btype: typedesc[Base32Types],
inbytes: openarray[byte]): string {.inline.} =
## Encode array of bytes ``inbytes`` using BASE32 encoding and return
## encoded string.
if len(inbytes) == 0:
result = ""
else:
var length = 0
result = newString(btype.encodedLength(len(inbytes)))
if btype.encode(inbytes, result, length) == Base32Status.Success:
result.setLen(length)
else:
result = ""
proc decode*[T: byte|char](btype: typedesc[Base32Types], instr: openarray[T],
outbytes: var openarray[byte], outlen: var int): Base32Status =
## Decode BASE32 string and store array of bytes to ``outbytes``. On success
## ``Base32Status.Success`` will be returned and ``outlen`` will be set
## to number of bytes stored.
##
## ## If length of ``outbytes`` is not enough to store decoded bytes, then
## ``Base32Status.Overrun`` will be returned and ``outlen`` will be set to
## number of bytes required.
when (btype is Base32Upper) or (btype is Base32UpperPad):
const alphabet = RFCUpperCaseAlphabet
elif (btype is Base32Lower) or (btype is Base32LowerPad):
const alphabet = RFCLowerCaseAlphabet
elif (btype is HexBase32Upper) or (btype is HexBase32UpperPad):
const alphabet = HEXUpperCaseAlphabet
elif (btype is HexBase32Lower) or (btype is HexBase32LowerPad):
const alphabet = HEXLowerCaseAlphabet
if len(instr) == 0:
outlen = 0
return Base32Status.Success
let length = btype.decodedLength(len(instr))
if length > len(outbytes):
outlen = length
return Base32Status.Overrun
var inlen = len(instr)
when (btype is Base32PadTypes):
for i in countdown(inlen - 1, 0):
if instr[i] != '=':
break
dec(inlen)
let reminder = inlen mod 8
let limit = inlen - reminder
var buffer: array[8, byte]
var i, k: int
while i < limit:
for j in 0..<8:
if (cast[byte](instr[i + j]) and 0x80'u8) != 0:
outlen = 0
return Base32Status.Incorrect
let ch = alphabet.decode[cast[int8](instr[i + j])]
if ch == -1:
outlen = 0
return Base32Status.Incorrect
buffer[j] = cast[byte](ch)
discard convert8to5(buffer, outbytes.toOpenArray(k, k + 4), 8)
k += 5
i += 8
var left = 0
if reminder != 0:
if reminder == 1 or reminder == 3 or reminder == 6:
outlen = 0
return Base32Status.Incorrect
for j in 0..<reminder:
if (cast[byte](instr[i + j]) and 0x80'u8) != 0:
outlen = 0
result = Base32Status.Incorrect
return
let ch = alphabet.decode[cast[int8](instr[i + j])]
if ch == -1:
outlen = 0
result = Base32Status.Incorrect
return
buffer[j] = cast[byte](ch)
left = convert8to5(buffer.toOpenArray(0, reminder - 1),
outbytes.toOpenArray(k, length - 1), reminder)
outlen = k + left
result = Base32Status.Success
proc decode*[T: byte|char](btype: typedesc[Base32Types],
instr: openarray[T]): seq[byte] =
## Decode BASE32 string ``instr`` and return sequence of bytes as result.
if len(instr) == 0:
result = newSeq[byte]()
else:
var length = 0
result = newSeq[byte](btype.decodedLength(len(instr)))
if btype.decode(instr, result, length) == Base32Status.Success:
result.setLen(length)
else:
raise newException(Base32Error, "Incorrect base32 string")

View File

@ -1,239 +0,0 @@
## Nim-Libp2p
## Copyright (c) 2018 Status Research & Development GmbH
## Licensed under either of
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
## * MIT license ([LICENSE-MIT](LICENSE-MIT))
## at your option.
## This file may not be copied, modified, or distributed except according to
## those terms.
## This module implements BASE58 encoding and decoding procedures.
## This module supports two variants of BASE58 encoding (Bitcoin and Flickr).
type
Base58Status* {.pure.} = enum
Error,
Success,
Incorrect,
Overrun
Base58Alphabet* = object
decode*: array[128, int8]
encode*: array[58, uint8]
BTCBase58* = object
## Type to use Bitcoin alphabet
FLCBase58* = object
## Type to use Flickr alphabet
Base58* = BtcBase58
## By default we are using Bitcoin alphabet
Base58C* = BTCBase58 | FLCBase58
## Supported types
Base58Error* = object of CatchableError
## Base58 specific exception type
proc newAlphabet58*(s: string): Base58Alphabet =
doAssert(len(s) == 58)
for i in 0..<len(s):
result.encode[i] = cast[uint8](s[i])
for i in 0..<len(result.decode):
result.decode[i] = -1
for i in 0..<len(result.encode):
result.decode[int(result.encode[i])] = int8(i)
const
BTCAlphabet* = newAlphabet58("123456789ABCDEFGHJKLMNPQRSTUV" &
"WXYZabcdefghijkmnopqrstuvwxyz")
FlickrAlphabet* = newAlphabet58("123456789abcdefghijkmnopqrstu" &
"vwxyzABCDEFGHJKLMNPQRSTUVWXYZ")
proc encodedLength*(btype: typedesc[Base58C], length: int): int =
## Return estimated length of BASE58 encoded value for plain length
## ``length``.
result = (length * 138) div 100 + 1
proc decodedLength*(btype: typedesc[Base58C], length: int): int =
## Return estimated length of decoded value of BASE58 encoded value of length
## ``length``.
result = length + 4
proc encode*(btype: typedesc[Base58C], inbytes: openarray[byte],
outstr: var openarray[char], outlen: var int): Base58Status =
## Encode array of bytes ``inbytes`` using BASE58 encoding and store
## result to ``outstr``. On success ``Base58Status.Success`` will be returned
## and ``outlen`` will be set to number of characters stored inside of
## ``outstr``. If length of ``outstr`` is not enough then
## ``Base58Status.Overrun`` will be returned and ``outlen`` will be set to
## number of characters required.
when btype is BTCBase58:
const alphabet = BTCAlphabet
elif btype is FLCBase58:
const alphabet = FlickrAlphabet
let binsz = len(inbytes)
var zcount = 0
while zcount < binsz and inbytes[zcount] == 0x00'u8:
inc(zcount)
let size = ((binsz - zcount) * 138) div 100 + 1
var buffer = newSeq[uint8](size)
var hi = size - 1
var i = zcount
var j = size - 1
while i < binsz:
var carry = uint32(inbytes[i])
j = size - 1
while (j > hi) or (carry != 0'u32):
carry = carry + uint32(256'u32 * buffer[j])
buffer[j] = cast[byte](carry mod 58)
carry = carry div 58
dec(j)
hi = j
inc(i)
j = 0
while (j < size) and (buffer[j] == 0x00'u8):
inc(j)
let needed = zcount + size - j
outlen = needed
if len(outstr) < needed:
result = Base58Status.Overrun
else:
for k in 0..<zcount:
outstr[k] = cast[char](alphabet.encode[0])
i = zcount
while j < size:
outstr[i] = cast[char](alphabet.encode[buffer[j]])
inc(j)
inc(i)
result = Base58Status.Success
proc encode*(btype: typedesc[Base58C],
inbytes: openarray[byte]): string {.inline.} =
## Encode array of bytes ``inbytes`` using BASE58 encoding and return
## encoded string.
var size = (len(inbytes) * 138) div 100 + 1
result = newString(size)
if btype.encode(inbytes, result.toOpenArray(0, size - 1),
size) == Base58Status.Success:
result.setLen(size)
else:
result = ""
proc decode*[T: byte|char](btype: typedesc[Base58C], instr: openarray[T],
outbytes: var openarray[byte], outlen: var int): Base58Status =
## Decode BASE58 string and store array of bytes to ``outbytes``. On success
## ``Base58Status.Success`` will be returned and ``outlen`` will be set
## to number of bytes stored.
##
## Length of ``outbytes`` must be equal or more then ``len(instr) + 4``.
##
## If ``instr`` has characters which are not part of BASE58 alphabet, then
## ``Base58Status.Incorrect`` will be returned and ``outlen`` will be set to
## ``0``.
##
## If length of ``outbytes`` is not enough to store decoded bytes, then
## ``Base58Status.Overrun`` will be returned and ``outlen`` will be set to
## number of bytes required.
when btype is BTCBase58:
const alphabet = BTCAlphabet
elif btype is FLCBase58:
const alphabet = FlickrAlphabet
if len(instr) == 0:
outlen = 0
return Base58Status.Success
let binsz = len(instr) + 4
if len(outbytes) < binsz:
outlen = binsz
return Base58Status.Overrun
var bytesleft = binsz mod 4
var zeromask: uint32
if bytesleft != 0:
zeromask = cast[uint32](0xFFFF_FFFF'u32 shl (bytesleft * 8))
let size = (binsz + 3) div 4
var buffer = newSeq[uint32](size)
var zcount = 0
while zcount < len(instr) and instr[zcount] == cast[char](alphabet.encode[0]):
inc(zcount)
for i in zcount..<len(instr):
if (cast[byte](instr[i]) and 0x80'u8) != 0:
outlen = 0
result = Base58Status.Incorrect
return
let ch = alphabet.decode[int8(instr[i])]
if ch == -1:
outlen = 0
result = Base58Status.Incorrect
return
var c = cast[uint32](ch)
for j in countdown(size - 1, 0):
let t = cast[uint64](buffer[j]) * 58 + c
c = cast[uint32]((t and 0x3F_0000_0000'u64) shr 32)
buffer[j] = cast[uint32](t and 0xFFFF_FFFF'u32)
if c != 0:
outlen = 0
result = Base58Status.Incorrect
return
if (buffer[0] and zeromask) != 0:
outlen = 0
result = Base58Status.Incorrect
return
var boffset = 0
var joffset = 0
if bytesleft == 3:
outbytes[boffset] = cast[uint8]((buffer[0] and 0xFF_0000'u32) shr 16)
inc(boffset)
bytesleft = 2
if bytesleft == 2:
outbytes[boffset] = cast[uint8]((buffer[0] and 0xFF00'u32) shr 8)
inc(boffset)
bytesleft = 1
if bytesleft == 1:
outbytes[boffset] = cast[uint8]((buffer[0] and 0xFF'u32))
inc(boffset)
joffset = 1
while joffset < size:
outbytes[boffset + 0] = cast[byte]((buffer[joffset] shr 0x18) and 0xFF)
outbytes[boffset + 1] = cast[byte]((buffer[joffset] shr 0x10) and 0xFF)
outbytes[boffset + 2] = cast[byte]((buffer[joffset] shr 0x8) and 0xFF)
outbytes[boffset + 3] = cast[byte](buffer[joffset] and 0xFF)
boffset += 4
inc(joffset)
outlen = binsz
var m = 0
while m < binsz:
if outbytes[m] != 0x00:
if zcount > m:
result = Base58Status.Overrun
return
break
inc(m)
dec(outlen)
if m < binsz:
moveMem(addr outbytes[zcount], addr outbytes[binsz - outlen], outlen)
outlen += zcount
result = Base58Status.Success
proc decode*(btype: typedesc[Base58C], instr: string): seq[byte] =
## Decode BASE58 string ``instr`` and return sequence of bytes as result.
if len(instr) > 0:
var size = len(instr) + 4
result = newSeq[byte](size)
if btype.decode(instr, result, size) == Base58Status.Success:
result.setLen(size)
else:
raise newException(Base58Error, "Incorrect base58 string")

View File

@ -1,238 +0,0 @@
## Nim-Libp2p
## Copyright (c) 2018 Status Research & Development GmbH
## Licensed under either of
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
## * MIT license ([LICENSE-MIT](LICENSE-MIT))
## at your option.
## This file may not be copied, modified, or distributed except according to
## those terms.
## This module implements BASE64 encoding and decoding procedures.
type
Base64Status* {.pure.} = enum
Error,
Success,
Incorrect,
Overrun
Base64Alphabet* = object
decode*: array[128, int8]
encode*: array[64, uint8]
Base64* = object
## Type to use RFC4648 alphabet without padding
Base64Pad* = object
## Type to use RFC4648 alphabet with padding
Base64Url* = object
## Type to use RFC4648 URL alphabet without padding
Base64UrlPad* = object
## Type to use RFC4648 URL alphabet with padding
Base64PadTypes* = Base64Pad | Base64UrlPad
## All types with padding support
Base64NoPadTypes* = Base64 | Base64Url
## All types without padding support
Base64Types* = Base64 | Base64Pad | Base64Url | Base64UrlPad
## All types
Base64Error* = object of CatchableError
## Base64 specific exception type
proc newAlphabet64*(s: string): Base64Alphabet =
doAssert(len(s) == 64)
for i in 0..<len(s):
result.encode[i] = cast[uint8](s[i])
for i in 0..<len(result.decode):
result.decode[i] = -1
for i in 0..<len(result.encode):
result.decode[int(result.encode[i])] = int8(i)
const
B64Alphabet* = newAlphabet64("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef" &
"ghijklmnopqrstuvwxyz0123456789+/")
B64UrlAlphabet* = newAlphabet64("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef" &
"ghijklmnopqrstuvwxyz0123456789-_")
proc encodedLength*(btype: typedesc[Base64Types],
length: int): int {.inline.} =
## Return estimated length of BASE64 encoded value for plain length
## ``length``.
result = (((length + 2) div 3) * 4) + 1
proc decodedLength*(btype: typedesc[Base64Types],
length: int): int {.inline.} =
## Return estimated length of decoded value of BASE64 encoded value of length
## ``length``.
when (btype is Base64Pad) or (btype is Base64UrlPad):
result = ((length + 3 - 1) div 3) * 4
elif (btype is Base64) or (btype is Base64Url):
result = (length * 4 + 3 - 1) div 3
proc encode*(btype: typedesc[Base64Types], inbytes: openarray[byte],
outstr: var openarray[char], outlen: var int): Base64Status =
## Encode array of bytes ``inbytes`` using BASE64 encoding and store
## result to ``outstr``.
##
## On success ``Base64Status.Success`` will be returned and ``outlen`` will
## be set to number of characters stored inside of ``outstr``.
##
## If length of ``outstr`` is not enough then ``Base64Status.Overrun`` will
## be returned and ``outlen`` will be set to number of characters required.
when (btype is Base64) or (btype is Base64Pad):
const alphabet = B64Alphabet
elif (btype is Base64Url) or (btype is Base64UrlPad):
const alphabet = B64UrlAlphabet
let length = len(inbytes)
if len(outstr) < btype.encodedLength(length):
outlen = btype.encodedLength(length)
result = Base64Status.Overrun
else:
var offset = 0
var i = 0
while i < (length - 2):
outstr[offset] = chr(alphabet.encode[(inbytes[i] shr 2) and 0x3F'u8])
inc(offset)
outstr[offset] = chr(alphabet.encode[((inbytes[i] and 0x03) shl 4) or
((inbytes[i + 1] and 0xF0) shr 4)])
inc(offset)
outstr[offset] = chr(alphabet.encode[((inbytes[i + 1] and 0x0F) shl 2) or
((inbytes[i + 2] and 0xC0) shr 6)])
inc(offset)
outstr[offset] = chr(alphabet.encode[inbytes[i + 2] and 0x3F])
inc(offset)
i += 3
if i < length:
outstr[offset] = chr(alphabet.encode[(inbytes[i] shr 2) and 0x3F])
inc(offset)
if i == length - 1:
outstr[offset] = chr(alphabet.encode[(inbytes[i] and 0x03) shl 4])
inc(offset)
when (btype is Base64Pad) or (btype is Base64UrlPad):
outstr[offset] = '='
inc(offset)
else:
outstr[offset] = chr(alphabet.encode[((inbytes[i] and 0x03) shl 4) or
((inbytes[i + 1] and 0xF0) shr 4)])
inc(offset)
outstr[offset] = chr(alphabet.encode[(inbytes[i + 1] and 0x0F) shl 2])
inc(offset)
when (btype is Base64Pad) or (btype is Base64UrlPad):
outstr[offset] = '='
inc(offset)
outlen = offset
result = Base64Status.Success
proc encode*(btype: typedesc[Base64Types],
inbytes: openarray[byte]): string {.inline.} =
## Encode array of bytes ``inbytes`` using BASE64 encoding and return
## encoded string.
var size = btype.encodedLength(len(inbytes))
result = newString(size)
if btype.encode(inbytes, result.toOpenArray(0, size - 1),
size) == Base64Status.Success:
result.setLen(size)
else:
result = ""
proc decode*[T: byte|char](btype: typedesc[Base64Types], instr: openarray[T],
outbytes: var openarray[byte], outlen: var int): Base64Status =
## Decode BASE64 string and store array of bytes to ``outbytes``. On success
## ``Base64Status.Success`` will be returned and ``outlen`` will be set
## to number of bytes stored.
##
## Length of ``outbytes`` must be equal or more then ``len(instr) + 4``.
##
## If ``instr`` has characters which are not part of BASE64 alphabet, then
## ``Base64Status.Incorrect`` will be returned and ``outlen`` will be set to
## ``0``.
##
## If length of ``outbytes`` is not enough to store decoded bytes, then
## ``Base64Status.Overrun`` will be returned and ``outlen`` will be set to
## number of bytes required.
when (btype is Base64) or (btype is Base64Pad):
const alphabet = B64Alphabet
elif (btype is Base64Url) or (btype is Base64UrlPad):
const alphabet = B64UrlAlphabet
if len(instr) == 0:
outlen = 0
return Base64Status.Success
let length = btype.decodedLength(len(instr))
if length > len(outbytes):
outlen = length
return Base64Status.Overrun
var inlen = len(instr)
when (btype is Base64PadTypes):
for i in countdown(inlen - 1, 0):
if instr[i] != '=':
break
dec(inlen)
let reminder = inlen mod 4
let limit = inlen - reminder
var buffer: array[4, byte]
var i, k: int
while i < limit:
for j in 0..<4:
if (cast[byte](instr[i + j]) and 0x80'u8) != 0:
outlen = 0
zeroMem(addr outbytes[0], i + 3)
return Base64Status.Incorrect
let ch = alphabet.decode[cast[int8](instr[i + j])]
if ch == -1:
outlen = 0
zeroMem(addr outbytes[0], i + 3)
return Base64Status.Incorrect
buffer[j] = cast[byte](ch)
outbytes[k] = cast[byte]((buffer[0] shl 2) or (buffer[1] shr 4))
inc(k)
outbytes[k] = cast[byte]((buffer[1] shl 4) or (buffer[2] shr 2))
inc(k)
outbytes[k] = cast[byte]((buffer[2] shl 6) or buffer[3])
inc(k)
i += 4
if reminder > 0:
if reminder == 1:
outlen = 0
return Base64Status.Incorrect
for j in 0..<reminder:
if (cast[byte](instr[i + j]) and 0x80'u8) != 0:
outlen = 0
return Base64Status.Incorrect
let ch = alphabet.decode[cast[int8](instr[i + j])]
if ch == -1:
outlen = 0
return Base64Status.Incorrect
buffer[j] = cast[byte](ch)
if reminder > 1:
outbytes[k] = cast[byte]((buffer[0] shl 2) or (buffer[1] shr 4))
inc(k)
if reminder > 2:
outbytes[k] = cast[byte]((buffer[1] shl 4) or (buffer[2] shr 2))
inc(k)
outlen = k
result = Base64Status.Success
proc decode*[T: byte|char](btype: typedesc[Base64Types],
instr: openarray[T]): seq[byte] =
## Decode BASE64 string ``instr`` and return sequence of bytes as result.
if len(instr) == 0:
result = newSeq[byte]()
else:
var length = 0
result = newSeq[byte](btype.decodedLength(len(instr)))
if btype.decode(instr, result, length) == Base64Status.Success:
result.setLen(length)
else:
raise newException(Base64Error, "Incorrect base64 string")

View File

@ -9,7 +9,8 @@
## This module implementes CID (Content IDentifier). ## This module implementes CID (Content IDentifier).
import tables import tables
import multibase, multicodec, multihash, vbuffer, varint, base58 import multibase, multicodec, multihash, vbuffer, varint
import stew/base58
type type
CidStatus* {.pure.} = enum CidStatus* {.pure.} = enum

View File

@ -9,8 +9,8 @@
## This module implementes API for `go-libp2p-daemon`. ## This module implementes API for `go-libp2p-daemon`.
import os, osproc, strutils, tables, streams, strtabs import os, osproc, strutils, tables, streams, strtabs
import chronos import chronos, stew/base58
import ../varint, ../multiaddress, ../multicodec, ../base58, ../cid, ../peer import ../varint, ../multiaddress, ../multicodec, ../cid, ../peer
import ../wire, ../multihash, ../protobuf/minprotobuf import ../wire, ../multihash, ../protobuf/minprotobuf
import ../crypto/crypto import ../crypto/crypto

View File

@ -11,7 +11,8 @@
import nativesockets import nativesockets
import tables, strutils, net import tables, strutils, net
import chronos import chronos
import multicodec, multihash, multibase, transcoder, base58, base32, vbuffer import multicodec, multihash, multibase, transcoder, vbuffer
import stew/[base58, base32]
from peer import PeerID from peer import PeerID
{.deadCodeElim:on.} {.deadCodeElim:on.}

View File

@ -12,7 +12,7 @@
## TODO: ## TODO:
## 1. base32z ## 1. base32z
import tables import tables
import base32, base58, base64 import stew/[base32, base58, base64]
type type
MultibaseStatus* {.pure.} = enum MultibaseStatus* {.pure.} = enum

View File

@ -22,8 +22,8 @@
## 2. MURMUR ## 2. MURMUR
import tables import tables
import nimcrypto/[sha, sha2, keccak, blake2, hash, utils] import nimcrypto/[sha, sha2, keccak, blake2, hash, utils]
import varint, vbuffer, base58, multicodec, multibase import varint, vbuffer, multicodec, multibase
import stew/base58
# This is workaround for Nim `import` bug. # This is workaround for Nim `import` bug.
export sha, sha2, keccak, blake2, hash, utils export sha, sha2, keccak, blake2, hash, utils

View File

@ -9,8 +9,8 @@
## This module implementes API for libp2p peer. ## This module implementes API for libp2p peer.
import hashes import hashes
import nimcrypto/utils import nimcrypto/utils, stew/base58
import crypto/crypto, multicodec, multihash, base58, vbuffer import crypto/crypto, multicodec, multihash, vbuffer
import protobuf/minprotobuf import protobuf/minprotobuf
const const

View File

@ -1,409 +0,0 @@
import unittest
import ../libp2p/base32
when defined(nimHasUsed): {.used.}
const TVBaseUpperPadding = [
["f", "MY======"],
["fo", "MZXQ===="],
["foo", "MZXW6==="],
["foob", "MZXW6YQ="],
["fooba", "MZXW6YTB"],
["foobar", "MZXW6YTBOI======"]
]
const TVBaseUpperNoPadding = [
["f", "MY"],
["fo", "MZXQ"],
["foo", "MZXW6"],
["foob", "MZXW6YQ"],
["fooba", "MZXW6YTB"],
["foobar", "MZXW6YTBOI"]
]
const TVBaseLowerPadding = [
["f", "my======"],
["fo", "mzxq===="],
["foo", "mzxw6==="],
["foob", "mzxw6yq="],
["fooba", "mzxw6ytb"],
["foobar", "mzxw6ytboi======"]
]
const TVBaseLowerNoPadding = [
["f", "my"],
["fo", "mzxq"],
["foo", "mzxw6"],
["foob", "mzxw6yq"],
["fooba", "mzxw6ytb"],
["foobar", "mzxw6ytboi"]
]
const TVHexUpperPadding = [
["f", "CO======"],
["fo", "CPNG===="],
["foo", "CPNMU==="],
["foob", "CPNMUOG="],
["fooba", "CPNMUOJ1"],
["foobar", "CPNMUOJ1E8======"]
]
const TVHexUpperNoPadding = [
["f", "CO"],
["fo", "CPNG"],
["foo", "CPNMU"],
["foob", "CPNMUOG"],
["fooba", "CPNMUOJ1"],
["foobar", "CPNMUOJ1E8"]
]
const TVHexLowerPadding = [
["f", "co======"],
["fo", "cpng===="],
["foo", "cpnmu==="],
["foob", "cpnmuog="],
["fooba", "cpnmuoj1"],
["foobar", "cpnmuoj1e8======"]
]
const TVHexLowerNoPadding = [
["f", "co"],
["fo", "cpng"],
["foo", "cpnmu"],
["foob", "cpnmuog"],
["fooba", "cpnmuoj1"],
["foobar", "cpnmuoj1e8"]
]
suite "BASE32 encoding test suite":
test "Empty seq/string test":
var empty1 = newSeq[byte]()
var empty2 = ""
var encoded = newString(16)
var decoded = newSeq[byte](16)
var o1, o2, o3, o4, o5, o6, o7, o8: int
var e1 = Base32Upper.encode(empty1)
var e2 = Base32Lower.encode(empty1)
var e3 = Base32UpperPad.encode(empty1)
var e4 = Base32LowerPad.encode(empty1)
var e5 = HexBase32Upper.encode(empty1)
var e6 = HexBase32Lower.encode(empty1)
var e7 = HexBase32UpperPad.encode(empty1)
var e8 = HexBase32LowerPad.encode(empty1)
check:
Base32Upper.encode(empty1, encoded, o1) == Base32Status.Success
Base32Lower.encode(empty1, encoded, o2) == Base32Status.Success
Base32UpperPad.encode(empty1, encoded, o3) == Base32Status.Success
Base32LowerPad.encode(empty1, encoded, o4) == Base32Status.Success
HexBase32Upper.encode(empty1, encoded, o5) == Base32Status.Success
HexBase32Lower.encode(empty1, encoded, o6) == Base32Status.Success
HexBase32UpperPad.encode(empty1, encoded, o7) == Base32Status.Success
HexBase32LowerPad.encode(empty1, encoded, o8) == Base32Status.Success
len(e1) == 0
len(e2) == 0
len(e3) == 0
len(e4) == 0
len(e5) == 0
len(e6) == 0
len(e7) == 0
len(e8) == 0
o1 == 0
o2 == 0
o3 == 0
o4 == 0
o5 == 0
o6 == 0
o7 == 0
o8 == 0
var d1 = Base32Upper.decode("")
var d2 = Base32Lower.decode("")
var d3 = Base32UpperPad.decode("")
var d4 = Base32LowerPad.decode("")
var d5 = HexBase32Upper.decode("")
var d6 = HexBase32Lower.decode("")
var d7 = HexBase32UpperPad.decode("")
var d8 = HexBase32LowerPad.decode("")
check:
Base32Upper.decode(empty2, decoded, o1) == Base32Status.Success
Base32Lower.decode(empty2, decoded, o2) == Base32Status.Success
Base32UpperPad.decode(empty2, decoded, o3) == Base32Status.Success
Base32LowerPad.decode(empty2, decoded, o4) == Base32Status.Success
HexBase32Upper.decode(empty2, decoded, o5) == Base32Status.Success
HexBase32Lower.decode(empty2, decoded, o6) == Base32Status.Success
HexBase32UpperPad.decode(empty2, decoded, o7) == Base32Status.Success
HexBase32LowerPad.decode(empty2, decoded, o8) == Base32Status.Success
len(d1) == 0
len(d2) == 0
len(d3) == 0
len(d4) == 0
len(d5) == 0
len(d6) == 0
len(d7) == 0
len(d8) == 0
o1 == 0
o2 == 0
o3 == 0
o4 == 0
o5 == 0
o6 == 0
o7 == 0
o8 == 0
test "Zero test":
var s = newString(256)
for i in 0..255:
s[i] = 'A'
var buffer: array[256, byte]
for i in 0..255:
var a = Base32.encode(buffer.toOpenArray(0, i))
var b = Base32.decode(a)
check b == buffer[0..i]
test "Leading zero test":
var buffer: array[256, byte]
for i in 0..255:
buffer[255] = byte(i)
var a = Base32.encode(buffer)
var b = Base32.decode(a)
check:
equalMem(addr buffer[0], addr b[0], 256) == true
test "BASE32 uppercase padding test vectors":
for item in TVBaseUpperPadding:
let plain = cast[seq[byte]](item[0])
let expect = item[1]
var elen = 0
var dlen = 0
var e1 = Base32UpperPad.encode(plain)
var e2 = newString(Base32UpperPad.encodedLength(len(plain)))
check:
Base32UpperPad.encode(plain, e2, elen) == Base32Status.Success
e2.setLen(elen)
check:
e1 == expect
e2 == expect
var d1 = Base32UpperPad.decode(expect)
var d2 = newSeq[byte](Base32UpperPad.decodedLength(len(expect)))
check:
Base32UpperPad.decode(expect, d2, dlen) == Base32Status.Success
d2.setLen(dlen)
check:
d1 == plain
d2 == plain
test "BASE32 lowercase padding test vectors":
for item in TVBaseLowerPadding:
let plain = cast[seq[byte]](item[0])
let expect = item[1]
var elen = 0
var dlen = 0
var e1 = Base32LowerPad.encode(plain)
var e2 = newString(Base32LowerPad.encodedLength(len(plain)))
check:
Base32LowerPad.encode(plain, e2, elen) == Base32Status.Success
e2.setLen(elen)
check:
e1 == expect
e2 == expect
var d1 = Base32LowerPad.decode(expect)
var d2 = newSeq[byte](Base32LowerPad.decodedLength(len(expect)))
check:
Base32LowerPad.decode(expect, d2, dlen) == Base32Status.Success
d2.setLen(dlen)
check:
d1 == plain
d2 == plain
test "BASE32 uppercase no-padding test vectors":
for item in TVBaseUpperNoPadding:
let plain = cast[seq[byte]](item[0])
let expect = item[1]
var elen = 0
var dlen = 0
var e1 = Base32Upper.encode(plain)
var e2 = newString(Base32Upper.encodedLength(len(plain)))
check:
Base32Upper.encode(plain, e2, elen) == Base32Status.Success
e2.setLen(elen)
check:
e1 == expect
e2 == expect
var d1 = Base32Upper.decode(expect)
var d2 = newSeq[byte](Base32Upper.decodedLength(len(expect)))
check:
Base32Upper.decode(expect, d2, dlen) == Base32Status.Success
d2.setLen(dlen)
check:
d1 == plain
d2 == plain
test "BASE32 lowercase no-padding test vectors":
for item in TVBaseLowerNoPadding:
let plain = cast[seq[byte]](item[0])
let expect = item[1]
var elen = 0
var dlen = 0
var e1 = Base32Lower.encode(plain)
var e2 = newString(Base32Lower.encodedLength(len(plain)))
check:
Base32Lower.encode(plain, e2, elen) == Base32Status.Success
e2.setLen(elen)
check:
e1 == expect
e2 == expect
var d1 = Base32Lower.decode(expect)
var d2 = newSeq[byte](Base32Lower.decodedLength(len(expect)))
check:
Base32Lower.decode(expect, d2, dlen) == Base32Status.Success
d2.setLen(dlen)
check:
d1 == plain
d2 == plain
test "HEX-BASE32 uppercase padding test vectors":
for item in TVHexUpperPadding:
let plain = cast[seq[byte]](item[0])
let expect = item[1]
var elen = 0
var dlen = 0
var e1 = HexBase32UpperPad.encode(plain)
var e2 = newString(HexBase32UpperPad.encodedLength(len(plain)))
check:
HexBase32UpperPad.encode(plain, e2, elen) == Base32Status.Success
e2.setLen(elen)
check:
e1 == expect
e2 == expect
var d1 = HexBase32UpperPad.decode(expect)
var d2 = newSeq[byte](HexBase32UpperPad.decodedLength(len(expect)))
check:
HexBase32UpperPad.decode(expect, d2, dlen) == Base32Status.Success
d2.setLen(dlen)
check:
d1 == plain
d2 == plain
test "HEX-BASE32 lowercase padding test vectors":
for item in TVHexLowerPadding:
let plain = cast[seq[byte]](item[0])
let expect = item[1]
var elen = 0
var dlen = 0
var e1 = HexBase32LowerPad.encode(plain)
var e2 = newString(HexBase32LowerPad.encodedLength(len(plain)))
check:
HexBase32LowerPad.encode(plain, e2, elen) == Base32Status.Success
e2.setLen(elen)
check:
e1 == expect
e2 == expect
var d1 = HexBase32LowerPad.decode(expect)
var d2 = newSeq[byte](HexBase32LowerPad.decodedLength(len(expect)))
check:
HexBase32LowerPad.decode(expect, d2, dlen) == Base32Status.Success
d2.setLen(dlen)
check:
d1 == plain
d2 == plain
test "HEX-BASE32 uppercase no-padding test vectors":
for item in TVHexUpperNoPadding:
let plain = cast[seq[byte]](item[0])
let expect = item[1]
var elen = 0
var dlen = 0
var e1 = HexBase32Upper.encode(plain)
var e2 = newString(HexBase32Upper.encodedLength(len(plain)))
check:
HexBase32Upper.encode(plain, e2, elen) == Base32Status.Success
e2.setLen(elen)
check:
e1 == expect
e2 == expect
var d1 = HexBase32Upper.decode(expect)
var d2 = newSeq[byte](HexBase32Upper.decodedLength(len(expect)))
check:
HexBase32Upper.decode(expect, d2, dlen) == Base32Status.Success
d2.setLen(dlen)
check:
d1 == plain
d2 == plain
test "HEX-BASE32 lowercase no-padding test vectors":
for item in TVHexLowerNoPadding:
let plain = cast[seq[byte]](item[0])
let expect = item[1]
var elen = 0
var dlen = 0
var e1 = HexBase32Lower.encode(plain)
var e2 = newString(HexBase32Lower.encodedLength(len(plain)))
check:
HexBase32Lower.encode(plain, e2, elen) == Base32Status.Success
e2.setLen(elen)
check:
e1 == expect
e2 == expect
var d1 = HexBase32Lower.decode(expect)
var d2 = newSeq[byte](HexBase32Lower.decodedLength(len(expect)))
check:
HexBase32Lower.decode(expect, d2, dlen) == Base32Status.Success
d2.setLen(dlen)
check:
d1 == plain
d2 == plain
test "Buffer Overrun test":
var encres = ""
var encsize = 0
var decres: seq[byte] = @[]
var decsize = 0
check:
Base32.encode([0'u8], encres, encsize) == Base32Status.Overrun
encsize == Base32.encodedLength(1)
Base32.decode("AA", decres, decsize) == Base32Status.Overrun
decsize == Base32.decodedLength(2)
test "Incorrect test":
var decres = newSeq[byte](10)
var decsize = 0
check:
Base32.decode("A", decres, decsize) == Base32Status.Incorrect
decsize == 0
Base32.decode("AAA", decres, decsize) == Base32Status.Incorrect
decsize == 0
Base32.decode("AAAAAA", decres, decsize) == Base32Status.Incorrect
decsize == 0
Base32Upper.decode("aa", decres, decsize) == Base32Status.Incorrect
decsize == 0
Base32Upper.decode("11", decres, decsize) == Base32Status.Incorrect
decsize == 0
Base32Lower.decode("AA", decres, decsize) == Base32Status.Incorrect
decsize == 0
Base32Lower.decode("11", decres, decsize) == Base32Status.Incorrect
decsize == 0
HexBase32Upper.decode("aa", decres, decsize) == Base32Status.Incorrect
decsize == 0
HexBase32Upper.decode("WW", decres, decsize) == Base32Status.Incorrect
decsize == 0
HexBase32Lower.decode("AA", decres, decsize) == Base32Status.Incorrect
decsize == 0
HexBase32Lower.decode("ww", decres, decsize) == Base32Status.Incorrect
decsize == 0

View File

@ -1,132 +0,0 @@
import unittest
import ../libp2p/base58
when defined(nimHasUsed): {.used.}
proc hexToBytes*(a: string, result: var openarray[byte]) =
doAssert(len(a) == 2 * len(result))
var i = 0
var k = 0
var r = 0
if len(a) > 0:
while i < len(a):
let c = a[i]
if i != 0 and i %% 2 == 0:
result[k] = r.byte
r = 0
inc(k)
else:
r = r shl 4
case c
of 'a'..'f':
r = r or (10 + ord(c) - ord('a'))
of 'A'..'F':
r = r or (10 + ord(c) - ord('A'))
of '0'..'9':
r = r or (ord(c) - ord('0'))
else:
doAssert(false)
inc(i)
result[k] = r.byte
proc fromHex*(a: string): seq[byte] =
doAssert(len(a) %% 2 == 0)
if len(a) == 0:
result = newSeq[byte]()
else:
result = newSeq[byte](len(a) div 2)
hexToBytes(a, result)
const TestVectors = [
["", ""],
["61", "2g"],
["626262", "a3gV"],
["636363", "aPEr"],
["73696d706c792061206c6f6e6720737472696e67", "2cFupjhnEsSn59qHXstmK2ffpLv2"],
["00eb15231dfceb60925886b67d065299925915aeb172c06647", "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L"],
["516b6fcd0f", "ABnLTmg"],
["bf4f89001e670274dd", "3SEo3LWLoPntC"],
["572e4794", "3EFU7m"],
["ecac89cad93923c02321", "EJDM8drfXA6uyA"],
["10c8511e", "Rt5zm"],
["00000000000000000000", "1111111111"],
["000111d38e5fc9071ffcd20b4a763cc9ae4f252bb4e48fd66a835e252ada93ff480d6dd43dc62a641155a5", "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"],
["000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", "1cWB5HCBdLjAuqGGReWE3R3CguuwSjw6RHn39s2yuDRTS5NsBgNiFpWgAnEx6VQi8csexkgYw3mdYrMHr8x9i7aEwP8kZ7vccXWqKDvGv3u1GxFKPuAkn8JCPPGDMf3vMMnbzm6Nh9zh1gcNsMvH3ZNLmP5fSG6DGbbi2tuwMWPthr4boWwCxf7ewSgNQeacyozhKDDQQ1qL5fQFUW52QKUZDZ5fw3KXNQJMcNTcaB723LchjeKun7MuGW5qyCBZYzA1KjofN1gYBV3NqyhQJ3Ns746GNuf9N2pQPmHz4xpnSrrfCvy6TVVz5d4PdrjeshsWQwpZsZGzvbdAdN8MKV5QsBDY"]
]
suite "BASE58 encoding test suite":
test "Empty seq/string test":
var a = Base58.encode([])
check len(a) == 0
var b = Base58.decode("")
check len(b) == 0
test "Zero test":
var s = newString(256)
for i in 0..255:
s[i] = '1'
var buffer: array[256, byte]
for i in 0..255:
var a = Base58.encode(buffer.toOpenArray(0, i))
check a == s[0..i]
var b = Base58.decode(a)
check b == buffer[0..i]
test "Leading zero test":
var buffer: array[256, byte]
for i in 0..255:
buffer[255] = byte(i)
var a = Base58.encode(buffer)
var b = Base58.decode(a)
check:
equalMem(addr buffer[0], addr b[0], 256) == true
test "Small amount of bytes test":
var buffer1: array[1, byte]
var buffer2: array[2, byte]
for i in 0..255:
buffer1[0] = byte(i)
var enc = Base58.encode(buffer1)
var dec = Base58.decode(enc)
check:
len(dec) == 1
dec[0] == buffer1[0]
for i in 0..255:
for k in 0..255:
buffer2[0] = byte(i)
buffer2[1] = byte(k)
var enc = Base58.encode(buffer2)
var dec = Base58.decode(enc)
check:
len(dec) == 2
dec[0] == buffer2[0]
dec[1] == buffer2[1]
test "Test Vectors test":
for item in TestVectors:
var a = fromHex(item[0])
var enc = Base58.encode(a)
var dec = Base58.decode(item[1])
check:
enc == item[1]
dec == a
test "Buffer Overrun test":
var encres = ""
var encsize = 0
var decres: seq[byte] = @[]
var decsize = 0
check:
Base58.encode([0'u8], encres, encsize) == Base58Status.Overrun
encsize == 1
Base58.decode("1", decres, decsize) == Base58Status.Overrun
decsize == 5
test "Incorrect test":
var decres = newSeq[byte](10)
var decsize = 0
check:
Base58.decode("l", decres, decsize) == Base58Status.Incorrect
decsize == 0
Base58.decode("2l", decres, decsize) == Base58Status.Incorrect
decsize == 0
Base58.decode("O", decres, decsize) == Base58Status.Incorrect
decsize == 0
Base58.decode("2O", decres, decsize) == Base58Status.Incorrect
decsize == 0

View File

@ -1,164 +0,0 @@
import unittest
import ../libp2p/base64
when defined(nimHasUsed): {.used.}
const TVBasePadding = [
["f", "Zg=="],
["fo", "Zm8="],
["foo", "Zm9v"],
["foob", "Zm9vYg=="],
["fooba", "Zm9vYmE="],
["foobar", "Zm9vYmFy"]
]
const TVBaseNoPadding = [
["f", "Zg"],
["fo", "Zm8"],
["foo", "Zm9v"],
["foob", "Zm9vYg"],
["fooba", "Zm9vYmE"],
["foobar", "Zm9vYmFy"]
]
suite "BASE64 encoding test suite":
test "Empty seq/string test":
var empty1 = newSeq[byte]()
var empty2 = ""
var encoded = newString(16)
var decoded = newSeq[byte](16)
var o1, o2, o3, o4: int
var e1 = Base64.encode(empty1)
var e2 = Base64Url.encode(empty1)
var e3 = Base64Pad.encode(empty1)
var e4 = Base64UrlPad.encode(empty1)
check:
Base64.encode(empty1, encoded, o1) == Base64Status.Success
Base64Url.encode(empty1, encoded, o2) == Base64Status.Success
Base64Pad.encode(empty1, encoded, o3) == Base64Status.Success
Base64UrlPad.encode(empty1, encoded, o4) == Base64Status.Success
len(e1) == 0
len(e2) == 0
len(e3) == 0
len(e4) == 0
o1 == 0
o2 == 0
o3 == 0
o4 == 0
var d1 = Base64.decode("")
var d2 = Base64Url.decode("")
var d3 = Base64Pad.decode("")
var d4 = Base64UrlPad.decode("")
check:
Base64.decode(empty2, decoded, o1) == Base64Status.Success
Base64Url.decode(empty2, decoded, o2) == Base64Status.Success
Base64Pad.decode(empty2, decoded, o3) == Base64Status.Success
Base64UrlPad.decode(empty2, decoded, o4) == Base64Status.Success
len(d1) == 0
len(d2) == 0
len(d3) == 0
len(d4) == 0
o1 == 0
o2 == 0
o3 == 0
o4 == 0
test "Zero test":
var s = newString(256)
for i in 0..255:
s[i] = 'A'
var buffer: array[256, byte]
for i in 0..255:
var a = Base64.encode(buffer.toOpenArray(0, i))
var b = Base64.decode(a)
check b == buffer[0..i]
test "Leading zero test":
var buffer: array[256, byte]
for i in 0..255:
buffer[255] = byte(i)
var a = Base64.encode(buffer)
var b = Base64.decode(a)
check:
equalMem(addr buffer[0], addr b[0], 256) == true
test "BASE64 padding test vectors":
for item in TVBasePadding:
let plain = cast[seq[byte]](item[0])
let expect = item[1]
var elen = 0
var dlen = 0
var e1 = Base64Pad.encode(plain)
var e2 = newString(Base64Pad.encodedLength(len(plain)))
check:
Base64Pad.encode(plain, e2, elen) == Base64Status.Success
e2.setLen(elen)
check:
e1 == expect
e2 == expect
var d1 = Base64Pad.decode(expect)
var d2 = newSeq[byte](Base64Pad.decodedLength(len(expect)))
check:
Base64Pad.decode(expect, d2, dlen) == Base64Status.Success
d2.setLen(dlen)
check:
d1 == plain
d2 == plain
test "BASE64 no padding test vectors":
for item in TVBaseNoPadding:
let plain = cast[seq[byte]](item[0])
let expect = item[1]
var elen = 0
var dlen = 0
var e1 = Base64.encode(plain)
var e2 = newString(Base64.encodedLength(len(plain)))
check:
Base64.encode(plain, e2, elen) == Base64Status.Success
e2.setLen(elen)
check:
e1 == expect
e2 == expect
var d1 = Base64.decode(expect)
var d2 = newSeq[byte](Base64.decodedLength(len(expect)))
check:
Base64.decode(expect, d2, dlen) == Base64Status.Success
d2.setLen(dlen)
check:
d1 == plain
d2 == plain
test "Buffer Overrun test":
var encres = ""
var encsize = 0
var decres: seq[byte] = @[]
var decsize = 0
check:
Base64.encode([0'u8], encres, encsize) == Base64Status.Overrun
encsize == Base64.encodedLength(1)
Base64.decode("AA", decres, decsize) == Base64Status.Overrun
decsize == Base64.decodedLength(2)
test "Incorrect test":
var decres = newSeq[byte](10)
var decsize = 0
check:
Base64.decode("A", decres, decsize) == Base64Status.Incorrect
decsize == 0
Base64.decode("AAAAA", decres, decsize) == Base64Status.Incorrect
decsize == 0
Base64.decode("!", decres, decsize) == Base64Status.Incorrect
decsize == 0
Base64.decode("!!", decres, decsize) == Base64Status.Incorrect
decsize == 0
Base64.decode("AA==", decres, decsize) == Base64Status.Incorrect
decsize == 0
Base64.decode("_-", decres, decsize) == Base64Status.Incorrect
decsize == 0
Base64Url.decode("/+", decres, decsize) == Base64Status.Incorrect
decsize == 0

View File

@ -1,4 +1,4 @@
import testvarint, testbase32, testbase58, testbase64 import testvarint
import testrsa, testecnist, tested25519, testsecp256k1, testcrypto import testrsa, testecnist, tested25519, testsecp256k1, testcrypto
import testmultibase, testmultihash, testmultiaddress, testcid, testpeer import testmultibase, testmultihash, testmultiaddress, testcid, testpeer

View File

@ -10,8 +10,8 @@
## Test vectors was made using Go implementation ## Test vectors was made using Go implementation
## https://github.com/libp2p/go-libp2p-peer ## https://github.com/libp2p/go-libp2p-peer
import unittest import unittest
import nimcrypto/utils import nimcrypto/utils, stew/base58
import ../libp2p/crypto/crypto, ../libp2p/peer, ../libp2p/base58 import ../libp2p/crypto/crypto, ../libp2p/peer
when defined(nimHasUsed): {.used.} when defined(nimHasUsed): {.used.}