Base58 Class
software.sava.core.encoding.Base58
Provides Base58 encoding and decoding for Solana public keys and signatures.
Encoding Methods
Encode to String
static String encode(byte[] input)
static String encode(byte[] input, int offset, int to)
Starting offset in input array
Encode to Char Array
static int encode(byte[] input, char[] output)
Destination char array (must be at least input.length * 2)
Starting index of encoded data in output array
static int encode(byte[] input, int offset, int to, char[] output)
Decoding Methods
static byte[] decode(String input)
Throws IllegalArgumentException if input contains invalid Base58 characters.
static byte[] decode(char[] input)
static byte[] decode(char[] input, int from, int len)
Validation Methods
static boolean isBase58(char c)
True if character is valid Base58
static boolean isBase58(String str)
True if all characters are valid Base58
static int nonBase58(String str)
Index of first invalid character, or -1 if all valid
Example Usage
import software.sava.core.encoding.Base58;
// Encode bytes to Base58
byte[] publicKey = new byte[32];
String encoded = Base58.encode(publicKey);
System.out.println(encoded); // "11111111111111111111111111111111"
// Decode Base58 string
String address = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
byte[] decoded = Base58.decode(address);
// Validate Base58 string
if (Base58.isBase58(address)) {
System.out.println("Valid address");
}
// Find invalid character
String invalid = "invalid-address-0OIl";
int pos = Base58.nonBase58(invalid);
if (pos >= 0) {
System.out.println("Invalid at position: " + pos);
}
ByteUtil Class
software.sava.core.encoding.ByteUtil
Utilities for reading and writing integers in little-endian format.
Write Methods
Integers
static void putInt16LE(byte[] b, int off, int val)
static void putInt16LE(byte[] b, int off, short val)
static void putInt32LE(byte[] b, int off, int val)
static void putInt64LE(byte[] b, int off, long val)
Floating Point
static void putFloat32LE(byte[] b, int off, float val)
static void putFloat32LE(byte[] b, int off, double val)
static void putFloat64LE(byte[] b, int off, double val)
Big Integers
static int putInt128LE(byte[] data, int offset, BigInteger val)
static int putInt256LE(byte[] data, int offset, BigInteger val)
Number of bytes written (16 or 32)
Read Methods
Integers
static int getInt8LE(byte[] b, int off)
Unsigned 8-bit value (0-255)
static short getInt16LE(byte[] b, int off)
static int getInt32LE(byte[] b, int off)
static long getInt64LE(byte[] b, int off)
Floating Point
static float getFloat32LE(byte[] b, int off)
static double getFloat64LE(byte[] b, int off)
Big Integers
static BigInteger getInt128LE(byte[] data, int offset)
static BigInteger getUInt128LE(byte[] data, int offset)
static BigInteger getInt256LE(byte[] data, int offset)
static BigInteger getUInt256LE(byte[] data, int offset)
Utility Methods
Reverse Bytes
static byte[] reverse(byte[] bytes)
static byte[] reverse(byte[] bytes, int len)
static byte[] reverse(byte[] bytes, int offset, int len)
New array with reversed bytes
Fixed Length Arrays
static byte[] fixedLength(byte[] bytes, int length)
Array padded with zeros to specified length
Throws IllegalArgumentException if input exceeds desired length.
static byte[] fixedLength(String val, int length)
static byte[] fixedLength(String val, int length, Charset charset)
Array Search
static int indexOf(byte[] data, byte[] sub)
Index of first occurrence, or -1 if not found
static int indexOf(byte[] data, int start, byte[] sub)
static int indexOf(byte[] data, int start, int end, byte[] sub, int subStart, int subEnd)
Example Usage
import software.sava.core.encoding.ByteUtil;
import java.math.BigInteger;
// Write integers
byte[] buffer = new byte[16];
ByteUtil.putInt32LE(buffer, 0, 12345);
ByteUtil.putInt64LE(buffer, 4, 9876543210L);
// Read integers
int value32 = ByteUtil.getInt32LE(buffer, 0);
long value64 = ByteUtil.getInt64LE(buffer, 4);
// Work with 128-bit integers
var bigInt = new BigInteger("340282366920938463463374607431768211455");
ByteUtil.putInt128LE(buffer, 0, bigInt);
var retrieved = ByteUtil.getUInt128LE(buffer, 0);
// Reverse bytes
byte[] original = {1, 2, 3, 4, 5};
byte[] reversed = ByteUtil.reverse(original);
// reversed = {5, 4, 3, 2, 1}
// Fixed length string
String seed = "vault";
byte[] fixedSeed = ByteUtil.fixedLength(seed, 32);
// Padded to 32 bytes with zeros
CompactU16Encoding Class
software.sava.core.encoding.CompactU16Encoding
Encodes integers (0 to 262,143) in compact variable-length format.
- 0-127: 1 byte
- 128-16,383: 2 bytes
- 16,384-262,143: 3 bytes
Encoding Methods
static byte[] encodeLength(int len)
Value to encode (0 to 262,143)
Encoded bytes (1-3 bytes)
static int encodeLength(byte[] out, int off, int len)
Number of bytes written (1, 2, or 3)
Decoding Methods
static int decode(byte[] out, int off)
Utility Methods
static int getByteLen(int len)
Number of bytes required (1, 2, or 3)
static int getByteLen(byte[] data, int offset)
Number of bytes in encoded value
static boolean signedByte(int bite)
True if byte has high bit set (multi-byte encoding)
Example Usage
import software.sava.core.encoding.CompactU16Encoding;
// Encode values
byte[] encoded1 = CompactU16Encoding.encodeLength(100);
// 1 byte: [100]
byte[] encoded2 = CompactU16Encoding.encodeLength(1000);
// 2 bytes: [0xe8, 0x07]
byte[] encoded3 = CompactU16Encoding.encodeLength(100000);
// 3 bytes
// Encode into buffer
byte[] buffer = new byte[10];
int written = CompactU16Encoding.encodeLength(buffer, 0, 5000);
System.out.println("Bytes written: " + written); // 2
// Decode
int value = CompactU16Encoding.decode(buffer, 0);
System.out.println("Decoded: " + value); // 5000
// Get byte length
int byteLen = CompactU16Encoding.getByteLen(100000);
System.out.println("Byte length: " + byteLen); // 3
// Check if multi-byte
boolean isMultiByte = CompactU16Encoding.signedByte(buffer[0]);
Use Cases
- Transaction Encoding: Account and instruction counts
- Lookup Tables: Address counts
- Vector Lengths: Borsh serialization
- Compact Indexing: Space-efficient indices
Encoding Details
1-byte encoding (values 0-127):
2-byte encoding (values 128-16,383):
3-byte encoding (values 16,384-262,143):
1xxxxxxx 1xxxxxxx 000000xx
The high bit (0x80) indicates continuation to the next byte.