157 lines
3.7 KiB
Go
157 lines
3.7 KiB
Go
package wallet
|
|
|
|
import (
|
|
"math/bits"
|
|
|
|
"github.com/phamminh0811/private-grpc/crypto"
|
|
"github.com/phamminh0811/private-grpc/nockchain"
|
|
)
|
|
|
|
var InitialBits = []bool{true, false, false, true, true, false, true, false, false, false, false, false, false, false, true, true, true, true, false, false, false, false, false, true, true, true, false, true, true, false, true, false, true, true, false, false, false, false, true, false, true, true, true, false}
|
|
|
|
func NumBitsUint64(v uint64) int {
|
|
if v == 0 {
|
|
return 0
|
|
}
|
|
return 64 - bits.LeadingZeros64(v)
|
|
}
|
|
|
|
func Uint64ToBitsLSB0(x uint64) []bool {
|
|
bits := make([]bool, 64)
|
|
for i := 0; i < 64; i++ {
|
|
bits[i] = ((x >> i) & 1) == 1
|
|
}
|
|
return bits
|
|
}
|
|
|
|
func BitsToUint64LSB0(bits []bool, start, sz int) uint64 {
|
|
var data uint64
|
|
for i := 0; i < sz; i++ {
|
|
if bits[start+i] {
|
|
data |= 1 << i // LSB0: bit 0 = least significant
|
|
}
|
|
}
|
|
return data
|
|
}
|
|
|
|
func BoolsToBytesLSB0(bits []bool) []byte {
|
|
if len(bits) == 0 {
|
|
return nil
|
|
}
|
|
n := (len(bits) + 7) / 8 // ceil division
|
|
bytes := make([]byte, n)
|
|
for i, bit := range bits {
|
|
if bit {
|
|
byteIdx := i / 8
|
|
bitIdx := i % 8
|
|
bytes[byteIdx] |= 1 << bitIdx // LSB0: least-significant bit first
|
|
}
|
|
}
|
|
return bytes
|
|
}
|
|
|
|
func BytesToBoolsLSB0(data []byte) []bool {
|
|
bools := make([]bool, len(data)*8)
|
|
for i, b := range data {
|
|
for j := 0; j < 8; j++ {
|
|
bools[i*8+j] = ((b >> j) & 1) == 1 // LSB0 order
|
|
}
|
|
}
|
|
return bools
|
|
}
|
|
|
|
func EncodeNoteData(noteData *nockchain.NockchainLock) []byte {
|
|
bits := InitialBits
|
|
|
|
numPubkeys := noteData.KeysRequired
|
|
numPubkeysSz := NumBitsUint64(uint64(numPubkeys))
|
|
numPubkeysSzSz := NumBitsUint64(uint64(numPubkeysSz))
|
|
|
|
bits = append(bits, false)
|
|
for i := 0; i < numPubkeysSzSz; i++ {
|
|
bits = append(bits, false)
|
|
}
|
|
bits = append(bits, true)
|
|
|
|
if numPubkeysSzSz > 1 {
|
|
numPubkeysSzBits := Uint64ToBitsLSB0(uint64(numPubkeysSz))
|
|
bits = append(bits, numPubkeysSzBits[0:numPubkeysSzSz-1]...)
|
|
}
|
|
|
|
numPubkeysBits := Uint64ToBitsLSB0(uint64(numPubkeys))
|
|
bits = append(bits, numPubkeysBits[0:numPubkeysSz]...)
|
|
bits = append(bits, []bool{true, false}...)
|
|
for _, pkStr := range noteData.Pubkeys {
|
|
pkHash := crypto.Base58ToTip5Hash(pkStr)
|
|
for i, hash := range pkHash {
|
|
if i != 4 {
|
|
bits = append(bits, []bool{true, false}...)
|
|
}
|
|
hashSz := NumBitsUint64(hash)
|
|
hashSzSz := NumBitsUint64(uint64(hashSz))
|
|
|
|
bits = append(bits, false)
|
|
for i := 0; i < hashSzSz; i++ {
|
|
bits = append(bits, false)
|
|
}
|
|
bits = append(bits, true)
|
|
|
|
if hashSzSz > 1 {
|
|
hashSzBits := Uint64ToBitsLSB0(uint64(hashSz))
|
|
bits = append(bits, hashSzBits[0:hashSzSz-1]...)
|
|
}
|
|
|
|
hashBits := Uint64ToBitsLSB0(hash)
|
|
bits = append(bits, hashBits[0:hashSz]...)
|
|
}
|
|
}
|
|
|
|
bits = append(bits, []bool{true, false, false, true, false, true, false, true}...)
|
|
return BoolsToBytesLSB0(bits)
|
|
}
|
|
|
|
func DecodeNoteData(blob []byte) *nockchain.NockchainLock {
|
|
bits := BytesToBoolsLSB0(blob)
|
|
|
|
start := len(InitialBits) + 1
|
|
count := 0
|
|
for !bits[start] {
|
|
start += 1
|
|
count += 1
|
|
}
|
|
start += 1
|
|
numPksSz := uint64(1)
|
|
if count > 1 {
|
|
numPksSz = BitsToUint64LSB0(bits, start, count-1)
|
|
start += count - 1
|
|
}
|
|
numPks := BitsToUint64LSB0(bits, start, int(numPksSz))
|
|
start += int(numPksSz)
|
|
start += 2
|
|
pkHash := [5]uint64{}
|
|
for i := 0; i < 5; i++ {
|
|
if i != 4 {
|
|
start += 2
|
|
}
|
|
start += 1
|
|
count := 0
|
|
for !bits[start] {
|
|
start += 1
|
|
count += 1
|
|
}
|
|
start += 1
|
|
hashSz := uint64(count)
|
|
if count > 1 {
|
|
hashSz = BitsToUint64LSB0(bits, start, count-1) + 1<<(count-1)
|
|
start += count - 1
|
|
}
|
|
hash := BitsToUint64LSB0(bits, start, int(hashSz))
|
|
start += int(hashSz)
|
|
pkHash[i] = hash
|
|
}
|
|
return &nockchain.NockchainLock{
|
|
KeysRequired: numPks,
|
|
Pubkeys: []string{crypto.Tip5HashToBase58(pkHash)},
|
|
}
|
|
}
|