commit 3e013d432d2bdfdc327702b6f0b9e2a34526f906 Author: WeebDataHoarder <57538841+WeebDataHoarder@users.noreply.github.com> Date: Sat May 27 17:37:14 2023 +0200 Initial commit, imported from https://git.gammaspectra.live/P2Pool/moneroutil commit 7b24ed2d11ce3f88ca88247778296d60a6129319 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c6cddb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,8 @@ +Monero Utilities +Copyright (c) 2013 Go Authors +Copyright (c) 2017 Paxos + +Portion of the code is Go Author's property, licensed under the BSD-3 license +Portion of the code is Paxos's property, licensed under the MIT license + +const.go and edwards25519.go are licensed under BSD-3 (see LICENSE-BSD), all other files are licensed under MIT (see LICENSE-MIT). diff --git a/LICENSE-BSD b/LICENSE-BSD new file mode 100644 index 0000000..7e33363 --- /dev/null +++ b/LICENSE-BSD @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..9c743d0 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,25 @@ +Monero Utilities +Copyright (c) 2017, Paxos + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT +OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH +THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/base58.go b/base58.go new file mode 100644 index 0000000..fda5204 --- /dev/null +++ b/base58.go @@ -0,0 +1,133 @@ +package base58 + +import ( + "encoding/binary" +) + +const base58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" + +const reverseBase58 = +// 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +/* 00 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + /* 10 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + /* 20 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + /* 30 */ "\xff\x00\x01\x02\x03\x04\x05\x06\x07\x08\xff\xff\xff\xff\xff\xff" + + /* 40 */ "\xff\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\xff\x11\x12\x13\x14\x15\xff" + + /* 50 */ "\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\xff\xff\xff\xff\xff" + + /* 60 */ "\xff\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\xff\x2c\x2d\x2e" + + /* 70 */ "\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\xff\xff\xff\xff\xff" + + /* 80 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + /* 90 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + /* a0 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + /* b0 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + /* c0 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + /* d0 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + /* e0 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + + /* f0 */ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + +func encodeChunk(raw []byte, buf []byte) []byte { + intToDecode := binary.BigEndian.Uint64(raw[:]) + + for intToDecode > 0 { + buf = append(buf, base58[intToDecode%58]) + intToDecode /= 58 + } + for len(buf) < 11 { + buf = append(buf, '1') + } + for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 { + buf[i], buf[j] = buf[j], buf[i] + } + return buf +} +func encodeChunkTail(raw []byte, buf []byte) []byte { + var data [8]byte + copy(data[8-len(raw):], raw) + + intToDecode := binary.BigEndian.Uint64(data[:]) + + for intToDecode > 0 { + buf = append(buf, base58[intToDecode%58]) + intToDecode /= 58 + } + for len(buf) < 7 { + buf = append(buf, '1') + } + for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 { + buf[i], buf[j] = buf[j], buf[i] + } + return buf +} + +func decodeChunk(buf []byte, encoded string) []byte { + var intResult uint64 + currentMultiplier := uint64(1) + for i := len(encoded) - 1; i >= 0; i-- { + intResult += currentMultiplier * uint64(reverseBase58[encoded[i]]) + // this can overflow, but only on the last iteration when i == 0 when all data is valid + currentMultiplier *= 58 + } + + var result [8]byte + binary.BigEndian.PutUint64(result[:], intResult) + switch len(encoded) { + case 0: + return append(buf, result[8:]...) + case 2: + return append(buf, result[7:]...) + case 3: + return append(buf, result[6:]...) + case 5: + return append(buf, result[5:]...) + case 6: + return append(buf, result[4:]...) + case 7: + return append(buf, result[3:]...) + case 9: + return append(buf, result[2:]...) + case 10: + return append(buf, result[1:]...) + case 11: + return append(buf, result[:]...) + default: + } + return nil +} + +func Encode(data ...[]byte) string { + //preallocate common case + combined := make([]byte, 0, 96) + for _, item := range data { + combined = append(combined, item...) + } + + result := make([]byte, 0, len(combined)*2) + buf := make([]byte, 0, len(combined)*2) + length := len(combined) + rounds := length / 8 + for i := 0; i < rounds; i++ { + result = append(result, encodeChunk(combined[i*8:(i+1)*8], buf[:0])...) + } + if length%8 > 0 { + result = append(result, encodeChunkTail(combined[rounds*8:], buf[:0])...) + } + return string(result) +} + +func Decode(data string) (result []byte) { + //common case + return DecodePreAllocated(make([]byte, 0, 69), data) +} + +func DecodePreAllocated(buf []byte, data string) (result []byte) { + result = buf + length := len(data) + rounds := length / 11 + for i := 0; i < rounds; i++ { + result = decodeChunk(result, data[i*11:i*11+11]) + } + if length%11 > 0 { + result = decodeChunk(result, data[rounds*11:]) + } + return +} diff --git a/base58_test.go b/base58_test.go new file mode 100644 index 0000000..fe2b982 --- /dev/null +++ b/base58_test.go @@ -0,0 +1,16 @@ +package base58 + +import ( + "bytes" + "testing" +) + +func TestEncodeDecodeMoneroBase58Bounds(t *testing.T) { + data := make([]byte, 2048) + for i := range data { + data[i] = 0xff + } + if bytes.Compare(Decode(Encode(data)), data) != 0 { + t.Fatal() + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..cf6ba00 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module git.gammaspectra.live/P2Pool/monero-base58 + +go 1.20