Added updates and Version info

This commit is contained in:
Robinson 2021-08-23 00:14:25 -06:00
parent 37ebd30cf3
commit 77a5b1285d
9 changed files with 161 additions and 46 deletions

View File

@ -113,6 +113,8 @@ tasks.jar.get().apply {
}
dependencies {
implementation("com.dorkbox:Updates:1.1")
// listed as compileOnly, since we will be using netty bytebuf utils if we ALREADY are using netty byte buffs. **We don't want a hard dependency.**
compileOnly("io.netty:netty-buffer:4.1.66.Final")
compileOnly("com.esotericsoftware:kryo:5.2.0")

View File

@ -17,8 +17,14 @@
* Converted to kotlin by ligi
* https://github.com/komputing/KBase58/blob/master/kbase58/src/main/kotlin/org/komputing/kbase58/Base58.kt
*/
@file:Suppress("unused")
package dorkbox.bytes
import dorkbox.bytes.Base58.CHECKSUM_SIZE
import dorkbox.bytes.Base58.ENCODED_ZERO
import dorkbox.bytes.Base58.divmod
/**
* Base58 is a way to encode Bitcoin addresses (or arbitrary data) as alphanumeric strings.
* <p>
@ -43,38 +49,50 @@ package dorkbox.bytes
* number of leading zeros (which are otherwise lost during the mathematical operations on the
* numbers), and finally represent the resulting base-58 digits as alphanumeric ASCII characters.
*/
object Base58 {
/**
* Gets the version number.
*/
const val version = BytesInfo.version
private const val ENCODED_ZERO = '1'
private const val CHECKSUM_SIZE = 4
private const val alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
private val alphabetIndices by lazy {
IntArray(128) { alphabet.indexOf(it.toChar()) }
}
/**
* Divides a number, represented as an array of bytes each containing a single digit
* in the specified base, by the given divisor. The given number is modified in-place
* to contain the quotient, and the return value is the remainder.
*
* @param number the number to divide
* @param firstDigit the index within the array of the first non-zero digit
* (this is used for optimization by skipping the leading zeros)
* @param base the base in which the number's digits are represented (up to 256)
* @param divisor the number to divide by (up to 256)
* @return the remainder of the division operation
*/
private fun divmod(number: ByteArray, firstDigit: UInt, base: UInt, divisor: UInt): UInt {
// this is just long division which accounts for the base of the input digits
var remainder = 0.toUInt()
for (i in firstDigit until number.size.toUInt()) {
val digit = number[i.toInt()].toUByte()
val temp = remainder * base + digit
number[i.toInt()] = (temp / divisor).toByte()
remainder = temp % divisor
init {
// Add this project to the updates system, which verifies this class + UUID + version information
dorkbox.updates.Updates.add(Base58::class.java, "f176cecea06e48e1a96d59c08a6e98c3", BytesInfo.version)
}
internal const val ENCODED_ZERO = '1'
internal const val CHECKSUM_SIZE = 4
internal const val alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
internal val alphabetIndices by lazy {
IntArray(128) { alphabet.indexOf(it.toChar()) }
}
/**
* Divides a number, represented as an array of bytes each containing a single digit
* in the specified base, by the given divisor. The given number is modified in-place
* to contain the quotient, and the return value is the remainder.
*
* @param number the number to divide
* @param firstDigit the index within the array of the first non-zero digit
* (this is used for optimization by skipping the leading zeros)
* @param base the base in which the number's digits are represented (up to 256)
* @param divisor the number to divide by (up to 256)
* @return the remainder of the division operation
*/
internal fun divmod(number: ByteArray, firstDigit: UInt, base: UInt, divisor: UInt): UInt {
// this is just long division which accounts for the base of the input digits
var remainder = 0.toUInt()
for (i in firstDigit until number.size.toUInt()) {
val digit = number[i.toInt()].toUByte()
val temp = remainder * base + digit
number[i.toInt()] = (temp / divisor).toByte()
remainder = temp % divisor
}
return remainder
}
return remainder
}
@ -84,33 +102,37 @@ private fun divmod(number: ByteArray, firstDigit: UInt, base: UInt, divisor: UIn
* @return the base58-encoded string
*/
fun ByteArray.encodeToBase58String(): String {
val input = copyOf(size) // since we modify it in-place
if (input.isEmpty()) {
return ""
}
// Count leading zeros.
var zeros = 0
while (zeros < input.size && input[zeros].toInt() == 0) {
++zeros
}
// Convert base-256 digits to base-58 digits (plus conversion to ASCII characters)
val encoded = CharArray(input.size * 2) // upper bound
var outputStart = encoded.size
var inputStart = zeros
while (inputStart < input.size) {
encoded[--outputStart] = alphabet[divmod(input, inputStart.toUInt(), 256.toUInt(), 58.toUInt()).toInt()]
encoded[--outputStart] = Base58.alphabet[Base58.divmod(input, inputStart.toUInt(), 256.toUInt(), 58.toUInt()).toInt()]
if (input[inputStart].toInt() == 0) {
++inputStart // optimization - skip leading zeros
}
}
// Preserve exactly as many leading encoded zeros in output as there were leading zeros in data.
while (outputStart < encoded.size && encoded[outputStart] == ENCODED_ZERO) {
++outputStart
}
while (--zeros >= 0) {
encoded[--outputStart] = ENCODED_ZERO
encoded[--outputStart] = Base58.ENCODED_ZERO
}
// Return encoded string (including encoded leading zeros).
return String(encoded, outputStart, encoded.size - outputStart)
}
@ -126,21 +148,24 @@ fun String.decodeBase58(): ByteArray {
if (isEmpty()) {
return ByteArray(0)
}
// Convert the base58-encoded ASCII chars to a base58 byte sequence (base58 digits).
val input58 = ByteArray(length)
for (i in 0 until length) {
val c = this[i]
val digit = if (c.toInt() < 128) alphabetIndices[c.toInt()] else -1
val digit = if (c.code < 128) Base58.alphabetIndices[c.toInt()] else -1
if (digit < 0) {
throw NumberFormatException("Illegal character $c at position $i")
}
input58[i] = digit.toByte()
}
// Count leading zeros.
var zeros = 0
while (zeros < input58.size && input58[zeros].toInt() == 0) {
++zeros
}
// Convert base-58 digits to base-256 digits.
val decoded = ByteArray(length)
var outputStart = decoded.size
@ -151,10 +176,12 @@ fun String.decodeBase58(): ByteArray {
++inputStart // optimization - skip leading zeros
}
}
// Ignore extra leading zeroes that were added during the calculation.
while (outputStart < decoded.size && decoded[outputStart].toInt() == 0) {
++outputStart
}
// Return decoded data (including original number of leading zeros).
return decoded.copyOfRange(outputStart - zeros, decoded.size)
}
@ -164,21 +191,21 @@ fun String.decodeBase58(): ByteArray {
*
* @return the base58-encoded string
*/
fun ByteArray.encodeToBase58WithChecksum() = ByteArray(size + CHECKSUM_SIZE).apply {
fun ByteArray.encodeToBase58WithChecksum() = ByteArray(size + Base58.CHECKSUM_SIZE).apply {
System.arraycopy(this@encodeToBase58WithChecksum, 0, this, 0, this@encodeToBase58WithChecksum.size)
val checksum = this@encodeToBase58WithChecksum.sha256().sha256()
System.arraycopy(checksum, 0, this, this@encodeToBase58WithChecksum.size, CHECKSUM_SIZE)
System.arraycopy(checksum, 0, this, this@encodeToBase58WithChecksum.size, Base58.CHECKSUM_SIZE)
}.encodeToBase58String()
fun String.decodeBase58WithChecksum(): ByteArray {
val rawBytes = decodeBase58()
if (rawBytes.size < CHECKSUM_SIZE) {
if (rawBytes.size < Base58.CHECKSUM_SIZE) {
throw Exception("Too short for checksum: $this l: ${rawBytes.size}")
}
val checksum = rawBytes.copyOfRange(rawBytes.size - CHECKSUM_SIZE, rawBytes.size)
val checksum = rawBytes.copyOfRange(rawBytes.size - Base58.CHECKSUM_SIZE, rawBytes.size)
val payload = rawBytes.copyOfRange(0, rawBytes.size - CHECKSUM_SIZE)
val payload = rawBytes.copyOfRange(0, rawBytes.size - Base58.CHECKSUM_SIZE)
val hash = payload.sha256().sha256()
val computedChecksum = hash.copyOfRange(0, CHECKSUM_SIZE)

View File

@ -62,15 +62,25 @@ import java.io.InputStream
* Modified from KRYO ByteBufferInput to use ByteBuf instead of ByteBuffer.
*/
class ByteBufInput : Input {
companion object {
/**
* Gets the version number.
*/
const val version = BytesInfo.version
init {
// Add this project to the updates system, which verifies this class + UUID + version information
dorkbox.updates.Updates.add(ByteBufInput::class.java, "f176cecea06e48e1a96d59c08a6e98c3", BytesInfo.version)
}
}
var byteBuf: ByteBuf? = null
private set
private var initialReaderIndex = 0
private var initialWriterIndex = 0
private var tempBuffer: ByteArray? = null
/** Creates an uninitialized Input, [.setBuffer] must be called before the Input is used. */
constructor() {}
/** Creates a new Input for reading from a direct [ByteBuf].
* @param bufferSize The size of the buffer. An exception is thrown if more bytes than this are read and
* [.fill] does not supply more bytes.
@ -83,7 +93,6 @@ class ByteBufInput : Input {
* @see .setBuffer
*/
/** Creates a new Input for reading from a [ByteBuf] which is filled with the specified bytes. */
@JvmOverloads
constructor(bytes: ByteArray?, offset: Int = 0, count: Int = bytes!!.size) {
requireNotNull(bytes) { "bytes cannot be null." }
setBuffer(Unpooled.wrappedBuffer(bytes, offset, count))
@ -111,7 +120,9 @@ class ByteBufInput : Input {
/** Throws [UnsupportedOperationException] because this input uses a ByteBuffer, not a byte[].
* @see .getByteBuf
*/
@Deprecated(" ")
@Deprecated("Use getByteBuf() instead",
ReplaceWith("getByteBuf()")
)
override fun getBuffer(): ByteArray {
throw UnsupportedOperationException("This input does not used a byte[], see #getByteBuf().")
}
@ -119,7 +130,9 @@ class ByteBufInput : Input {
/** Throws [UnsupportedOperationException] because this input uses a ByteBuffer, not a byte[].
* @see .setBuffer
*/
@Deprecated(" ")
@Deprecated("Use setByteBuf() instead",
ReplaceWith("setByteBuf(ByteBuf)")
)
override fun setBuffer(bytes: ByteArray) {
throw UnsupportedOperationException("This input does not used a byte[], see #setByteBuf(ByteBuf).")
}

View File

@ -62,10 +62,23 @@ import java.io.OutputStream
* Modified from KRYO to use ByteBuf.
*/
class ByteBufOutput : Output {
companion object {
/**
* Gets the version number.
*/
const val version = BytesInfo.version
init {
// Add this project to the updates system, which verifies this class + UUID + version information
dorkbox.updates.Updates.add(ByteBufOutput::class.java, "f176cecea06e48e1a96d59c08a6e98c3", BytesInfo.version)
}
}
/** Returns the buffer. The bytes between zero and [.position] are the data that has been written. */
// NOTE: capacity IS NOT USED!
var byteBuf: ByteBuf? = null
private set
private var initialReaderIndex = 0
private var initialWriterIndex = 0

View File

@ -1,4 +1,4 @@
/*
/*
* Copyright 2021 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -52,6 +52,16 @@ import kotlin.experimental.and
@Suppress("unused", "DuplicatedCode", "DuplicatedCode", "MemberVisibilityCanBePrivate")
class ByteBuffer2 {
companion object {
/**
* Gets the version number.
*/
const val version = BytesInfo.version
init {
// Add this project to the updates system, which verifies this class + UUID + version information
dorkbox.updates.Updates.add(ByteBuffer2::class.java, "f176cecea06e48e1a96d59c08a6e98c3", BytesInfo.version)
}
/**
* Returns the number of bytes that would be written with [.writeInt].
*/

View File

@ -0,0 +1,23 @@
/*
* Copyright 2021 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.bytes
object BytesInfo {
/**
* Gets the version number.
*/
const val version = "1.2"
}

View File

@ -1,3 +1,18 @@
/*
* Copyright 2021 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.bytes
import java.security.MessageDigest

View File

@ -27,6 +27,16 @@ package dorkbox.bytes
public value class HexString(val string: String)
object Hex {
/**
* Gets the version number.
*/
const val version = BytesInfo.version
init {
// Add this project to the updates system, which verifies this class + UUID + version information
dorkbox.updates.Updates.add(Hex::class.java, "f176cecea06e48e1a96d59c08a6e98c3", BytesInfo.version)
}
/**
* Represents all the chars used for nibble
*/

View File

@ -1,6 +1,8 @@
module dorkbox.bytes {
exports dorkbox.bytes;
requires dorkbox.updates;
requires static com.esotericsoftware.kryo;
requires static io.netty.common;
requires static io.netty.buffer;