Merge branch 'protocol'

This commit is contained in:
херетик
2023-02-26 10:14:35 +00:00
10 changed files with 565 additions and 5 deletions

1
go.mod
View File

@@ -5,6 +5,7 @@ go 1.19
require (
git-indra.lan/indra-labs/lnd v0.15.5-beta
github.com/btcsuite/btcd/btcutil v1.1.3
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d
github.com/cybriq/qu v0.1.2
github.com/davecgh/go-spew v1.1.1
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0

1
go.sum
View File

@@ -154,6 +154,7 @@ github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOF
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcwallet v0.16.5 h1:4DTJ5aYAJomcR0jAb6JP8D0wNSxfz4H7WN/RBtNZY4o=
github.com/btcsuite/btcwallet v0.16.5/go.mod h1:mM19pFB3lGVxOL+kvHhHZAhdSWXKsZGiHvpJVvxL0D8=

154
pkg/b32/based32/based32.go Normal file
View File

@@ -0,0 +1,154 @@
// Package based32 provides a simplified variant of the standard
// Bech32 human readable binary codec
//
// This codec simplifies the padding algorithm compared to the Bech32 standard
// BIP 0173 by performing all of the check validation with the decoded bits
// instead of separating the pads of each segment.
package based32
import (
"encoding/base32"
"fmt"
"git-indra.lan/indra-labs/indra"
"git-indra.lan/indra-labs/indra/pkg/b32/codec"
"git-indra.lan/indra-labs/indra/pkg/crypto/sha256"
log2 "git-indra.lan/indra-labs/indra/pkg/proc/log"
"git-indra.lan/indra-labs/indra/pkg/util/slice"
)
var (
log = log2.GetLogger(indra.PathBase)
check = log.E.Chk
)
// charset is the set of characters used in the data section of bech32 strings.
// Note that this is ordered, such that for a given charset[i], i is the binary
// value of the character.
const charset = "abcdefghijklmnopqrstuvwxyz234569"
// Codec provides the encoder/decoder implementation created by makeCodec.
var Codec = makeCodec(
"Base32Check",
charset,
"",
)
func getCheckLen(length int) (checkLen int) {
lengthMod := (2 + length) % 5
checkLen = 5 - lengthMod + 1
return checkLen
}
func getCutPoint(length, checkLen int) int {
return length - checkLen - 1
}
// Shift5bitsLeft allows the elimination of the first 5 bits of the value,
// which are always zero in standard base32 encoding when based on a base 2
// value.
func Shift5bitsLeft(b slice.Bytes) (o slice.Bytes) {
o = make(slice.Bytes, len(b))
for i := range b {
if i != len(b)-1 {
o[i] = b[i] << 5
o[i] += b[i+1] >> 3
} else {
o[i] = b[i] << 5
}
}
return
}
func Shift5bitsRight(b slice.Bytes) (o slice.Bytes) {
o = make(slice.Bytes, len(b))
for i := range b {
if i == 0 {
o[i] = b[i] >> 5
} else {
o[i] = b[i] >> 5
o[i] += b[i-1] << 3
}
}
return
}
func makeCodec(
name string,
cs string,
hrp string,
) (cdc *codec.Codec) {
cdc = &codec.Codec{
Name: name,
Charset: cs,
HRP: hrp,
}
cdc.MakeCheck = func(input []byte, checkLen int) (output []byte) {
checkArray := sha256.Single(input)
return checkArray[:checkLen]
}
enc := base32.NewEncoding(cdc.Charset)
cdc.Encoder = func(input []byte) (output string, e error) {
if len(input) < 1 {
e = fmt.Errorf("cannot encode zero length to based32")
return
}
checkLen := getCheckLen(len(input))
outputBytes := make([]byte, len(input)+checkLen+1)
outputBytes[0] = byte(checkLen)
copy(outputBytes[1:len(input)+1], input)
copy(outputBytes[len(input)+1:], cdc.MakeCheck(input, checkLen))
outputBytes = Shift5bitsLeft(outputBytes)
outputString := enc.EncodeToString(outputBytes)
output = cdc.HRP + outputString[:len(outputString)-1]
return
}
cdc.Check = func(input []byte) (e error) {
switch {
case len(input) < 1:
e = fmt.Errorf("cannot encode zero length to based32")
return
case input == nil:
e = fmt.Errorf("cannot encode nil slice to based32")
return
}
checkLen := int(input[0])
if len(input) < checkLen+1 {
e = fmt.Errorf("data too short to have a check")
return
}
cutPoint := getCutPoint(len(input), checkLen)
payload, checksum := input[1:cutPoint], string(input[cutPoint:])
computedChecksum := string(cdc.MakeCheck(payload, checkLen))
valid := checksum != computedChecksum
if !valid {
e = fmt.Errorf("check failed")
}
return
}
cdc.Decoder = func(input string) (output []byte, e error) {
input = input[len(cdc.HRP):] + "q"
data := make([]byte, len(input)*5/8)
var writtenBytes int
writtenBytes, e = enc.Decode(data, []byte(input))
if check(e) {
return
}
data = Shift5bitsRight(data)
// The first byte signifies the length of the check at the end
checkLen := int(data[0])
if writtenBytes < checkLen+1 {
e = fmt.Errorf("check too short")
return
}
e = cdc.Check(data)
if e != nil {
return
}
output = data[1:getCutPoint(len(data)+1, checkLen)]
return
}
return cdc
}

View File

@@ -0,0 +1,183 @@
package based32
import (
"encoding/binary"
"encoding/hex"
"fmt"
"math/rand"
"testing"
"git-indra.lan/indra-labs/indra/pkg/crypto/sha256"
)
const (
seed = 1234567890
numKeys = 32
)
func TestCodec(t *testing.T) {
// Generate 10 pseudorandom 64 bit values. We do this here rather than
// pre-generating this separately as ultimately it is the same thing, the
// same seed produces the same series of pseudorandom values, and the hashes
// of these values are deterministic.
rand.Seed(seed)
seeds := make([]uint64, numKeys)
for i := range seeds {
seeds[i] = rand.Uint64()
}
// Convert the uint64 values to 8 byte long slices for the hash function.
seedBytes := make([][]byte, numKeys)
for i := range seedBytes {
seedBytes[i] = make([]byte, 8)
binary.LittleEndian.PutUint64(seedBytes[i], seeds[i])
}
// Generate hashes from the seeds
hashedSeeds := make([][]byte, numKeys)
// Uncomment lines relating to this variable to regenerate expected data
// that will log to console during test run.
generated := "\nexpected := []string{\n"
for i := range hashedSeeds {
hashed := sha256.Single(seedBytes[i])
hashedSeeds[i] = hashed[:]
generated += fmt.Sprintf("\t\"%x\",\n", hashedSeeds[i])
}
generated += "}\n"
t.Log(generated)
expected := []string{
"ee94d6cef460b180c995b2f8672e53006aced15fe4d5cc0da332d041feaa1514",
"0f92907a4d76ece96b042e2cbd60e2378039cc92c95ac99f73e8eacbdd38a7d3",
"dc0892182d0f4dd8643d6e1c29442cf96c2d0a0a985b747a747d96a4f87e06dc",
"fa1066bd91acc3a16eb08d6c5ef5893ff8a0d01525bb30cd6be66cea34f3b4b6",
"7eef96527a625f6489e1ca37377184daaa7d4ceb3cafc091f34fdc0357101fab",
"5ea29a714835e54ae1fd5549e10436a2619d1b8ae909468d3700903ae871c8c0",
"41070be84762fc76a36c0f3506c3dc90e78fc12ac5f3cd3e38c6e73c6d6ff427",
"2e19378670d2dd76d89f9e29d28213b0f2e0dd673ad6b9c5ab27b34772ca30f3",
"343134a858ca19cc988f30a2503729dcb83a544e2cc7eb3ca637110759afe782",
"70548744c390460b47a035dcbc7a72534172fa7ec1260659830bc587ea78ce18",
"13adbec37cbbe311fca9c9d37a884cad590ab362615cbf0ea275ab4d29c77a8d",
"ff145ee2c983438b15d3111365e45a8f4c7390e0d2d3e750036bb6b97dc72f96",
"f9fea53c3eac4866e637e11afe1766f22a168f9e99e8998d4d5c4cd885a99811",
"5b9ca521047cc06261acc6b3dcb7c6ac340a0b384a464987c7a45ff5c2283707",
"7f0451e8c9a294335238839159fc2ee850ac21b234444fef8af2088b2661103a",
"24fe6c69e5217befdf0325f52e35673f1cb5f674592fd82c612931ebaa22c37e",
"d89275ca53104332d20acd14d3112a08684be50f4947c730ece6b3443c444a5f",
"02674760e23fb0c5780e2514c2aeffa797207b2db97f4abf7208ed396d0d48b3",
"da477ff2ef2f9194bb21ca766038b120e2068fcb0662c4f63e39eeb68c9c1631",
"9435716f250de2d33fe4c76d143d31ffa7e1d536f64456625a5b52d7c5bb1ff1",
"b79033f579221800651b767612ece7f8b08f4a52565f72ef1ceca707c8d0ffb1",
"bd451c36d6487842378951ca94725699ccb28fecab1851ea50e8073a68e1ee44",
"be94236d0204998274ed5ae3ea7198b7f839f3642b04c83b35e37a48ba13b186",
"017d82fb33d0f1f0873a18d8dafa9b85b35ec70af1715d3f9d3d204532b3660e",
"97047d8ec8f6f49ea7152e6626e1c7e8e32c2e9dc6a60b6c1030b654772883a2",
"2634e9a3bf48d55eab32623b14b323ea4d3603e4c5fce573bfd7ebae33e69eaf",
"f8bc405edbaa4423f7b272649d79495c5cd0dbd39cb60484e9c3f6b828b320fc",
"d8a2f7aa2021e3c77cd04df8b60330c5b79d3cc5cdd156e86fb3a0fb34b0685d",
"5c381d4c470c99d7beb596a359be35fd9bb455b088031c45368b9928ce66a774",
"83b77abed4c677e169802de0c4b6176230fe4e673fa29b801fbdbde34d1e47e7",
"12b40270e989ddc550f74a2a66f6092903fe0ec075df2826148fa9080aa933b3",
"4db6259bb154e007bfe5be06a641bb3a797b4deaa9447d2f6d4deeed3f6ad07a",
}
for i := range hashedSeeds {
if expected[i] != hex.EncodeToString(hashedSeeds[i]) {
t.Log("failed", i, "expected", expected[1], "found", hashedSeeds)
t.FailNow()
}
}
encodedStr := []string{
"lxjjvwo6rqldagjswzpqzzokmagvtwrl9snltanumznaqp6vikrjoja",
"mhzfed2jv3oz2llaqxczpla4i3yaoomslevvsm9opuovs65hctzzwqc",
"toareqyfuhu3wdehvxbykkeft4wylikbkmfw5d2or6znjhyp2zn6qd4",
"x5bazv5sgwmhilowcgwyxxvre99rigqcus3wmgnnptgz2rugdlwfcaz",
"z9o9fsspjrf6zej4hfdon3rqtnku9km5m6k9qer6nh5yaz4v9raaqd9",
"jpkfgtrja26ksxb9vkutyieg2rgdhi3rluqsrung4ajaoxiohemafyt",
"naqoc9ii5rpy5vdnqhtkbwd3siopd6bflc9htj6hddoopdnn92pp3zu",
"qxbsn4godjn25wyt6pctuuccoypfyg5m45nnoofvmt3gr3szjanslus",
"u2dcnfildfbtteyr4ykeubxfholqosujywmp2z4uy3rcb2zdzlswnai",
"zyfjb2eyoiemc2hua25zpd2ojjuc4x2p3asmbszqmf4lb3enkwhwgg5",
"ij23pwdps56gep4vhe5g6uijswvscvtmjqvzpyouj22wtjjy55i3mno",
"p9rixxczgbuhcyv2mirgzpelkhuy44q4djnhz2qanv3nol5y4x5tdep",
"t495jj4h2weqzxgg9qrv9qxm3zcufupt2m6rgmnjvoezwefvhcf2v45",
"vnzzjjbar6maytbvtdlhxfxy2wdicqlhbfemsmhy6sf95ocpytfukaq",
"z9qiupizgrjim2shcbzcwp4f3ufblbbwi2eit9prlzarc9q9gsetxo5",
"isp43dj4uqxx369ams9klrvm49rznpworms9wbmmeutd25kelbx53f5",
"pmje5okkmiegmwsblgrjuyrfiegqs9fb5euprzq5ttlgrb4irfj6s32",
"qbgor3a4i93brlybysrjqvo96tzoid3fw4x6sv9oieo2olnbubxf3xs",
"xneo99s54xzdff3ehfhmybyweqoebupzmdgfrhwhy465numhjpnep3y",
"2kdk4lpeug6fuz94tdw2fb5gh92pyovg33eivtcljnvfv6jbtof3zsm",
"k3zam9vperbqadfdn3hmexm494lbd2kkjlf64xpdtwkob6i2d93d5zo",
"o6ukhbw2zehqqrxrfi4vfdsk2m4zmup5svrqupkkduaooti4hxocgwt",
"s9jii3naicjtatu5vnoh2trtc39qoptmqvqjsb3gxrxusf2cplzvtpq",
"uax3ax3gpipd4ehhimnrwx2toc3gxwhblyxcxj9tu6sarjsfdsyl5gl",
"2lqi9mozd3pjhvhcuxgmjxby9uoglbotxdkmc3mcaylmvf2xfs2jls9",
"itdj2ndx5enkxvlgjrdwfftepve2nqd4tc9zzltx9l6xlrt42pk9zcg",
"p4lyqc63oveii9xwjzgjhlzjfofzug32oolmbee5hb9nobiwmqpgjq3",
"tmkf55keaq6hr342bg9rnqdgdc3phj4yxg5cvxin6z2b6zuwahsixay",
"vodqhkmi4gjtv56wwlkgwn6gx6zxncvwceaghcfg2fzskgoispki5hj",
"2b3o6v62tdhpyljqaw6brfwc5rdb9som492fg4ad6633y9hpvgmmfq9",
"ijliatq5ge53rkq65fcuzxwbeuqh9qoyb256kbgcsh2scakvez3g3nb",
"ng3mjm3wfkoab594w9anjsbxm5hs62n5kuui9jpnvg653j9nlicwbv5",
}
encoded := "\nencodedStr := []string{\n"
// Convert hashes to our base32 encoding format
for i := range hashedSeeds {
// Note that we are slicing off a number of bytes at the end according
// to the sequence number to get different check byte lengths from a
// uniform original data. As such, this will be accounted for in the
// check by truncating the same amount in the check (times two, for the
// hex encoding of the string).
encode, err := Codec.Encode(hashedSeeds[i][:len(hashedSeeds[i])-i%5])
if err != nil {
t.Fatal(err)
}
if encode != encodedStr[i] {
t.Errorf(
"Decode failed, expected item %d '%s' got '%s'",
i, encodedStr[i], encode,
)
}
encoded += "\t\"" + encode + "\",\n"
}
encoded += "}\n"
t.Log(encoded)
// Next, decode the encodedStr above, which should be the output of the
// original generated seeds, with the index mod 5 truncations performed on
// each as was done to generate them.
for i := range encodedStr {
res, err := Codec.Decode(encodedStr[i])
if err != nil {
t.Fatalf("error: '%v'", err)
}
elen := len(expected[i])
etrimlen := 2 * (i % 5)
expectedHex := expected[i][:elen-etrimlen]
resHex := fmt.Sprintf("%x", res)
if resHex != expectedHex {
t.Fatalf(
"got: '%s' expected: '%s'",
resHex,
expectedHex,
)
}
}
}

102
pkg/b32/codec/types.go Normal file
View File

@@ -0,0 +1,102 @@
package codec
import (
"git-indra.lan/indra-labs/indra/pkg/b32/codecer"
)
// Codec is the collection of elements that creates a Human Readable Binary
// Transcription Codec
//
// This is an example of the use of a structure definition to encapsulate and
// logically connect together all of the elements of an implementation, while
// also permitting this to be used by external code without further
// dependencies, either through this type, or via the interface defined further
// down.
//
// It is not "official" idiom, but it's the opinion of the author of this
// tutorial that return values given in type specifications like this helps the
// users of the library understand what the return values actually are.
// Otherwise, the programmer is forced to read the whole function just to spot
// the names and, even worse, comments explaining what the values are, which are
// often neglected during debugging, and turn into lies!
type Codec struct {
// Name is the human readable name given to this encoder
Name string
// HRP is the Human Readable Prefix to be appended in front of the encoding
// to disambiguate it from another encoding or as a network or protocol
// identifier. This can be empty, but more usually this will be used to
// disambiguate versus other similarly encoded values, such as used on a
// different cryptocurrency network, or between main and test networks.
HRP string
// Charset is the set of characters that the encoder uses. This should match
// the output encoder, 32 for using base32, 64 for base64, etc.
//
// For arbitrary bases, see the following function in the standard library:
// https://cs.opensource.google/go/go/+/refs/tags/go1.17.7:src/strconv/itoa.go;l=25
// This function can render up to base36, but by default uses 0-9a-z in its
// representation, which would either need to be string substituted for
// non-performance-critical uses or the function above forked to provide a
// direct encoding to the intended characters used for the encoding, using
// this charset string as the key. The sequence matters, each character
// represents the cipher for a given value to be found at a given place in
// the encoded number.
Charset string
// Encode takes an arbitrary length byte input and returns the output as
// defined for the codec
Encoder func(input []byte) (output string, err error)
// Decode takes an encoded string and returns if the encoding is valid and
// the value passes any check function defined for the type.
Decoder func(input string) (output []byte, err error)
// AddCheck is used by Encode to add extra bytes for the checksum to ensure
// correct input so user does not send to a wrong address by mistake, for
// example.
MakeCheck func(input []byte, checkLen int) (output []byte)
// Check returns whether the check is valid
Check func(input []byte) (err error)
}
// The following implementations are here to ensure this type implements the
// interface. In this tutorial/example we are creating a kind of generic
// implementation through the use of closures loaded into a struct.
//
// Normally a developer would use either one, or the other, a struct with
// closures, OR an interface with arbitrary variable with implementations for
// the created type.
//
// In order to illustrate both interfaces and the use of closures with a struct
// in this way we combine the two things by invoking the closures in a
// predefined pair of methods that satisfy the interface.
//
// In fact, there is no real reason why this design could not be standard idiom,
// since satisfies most of the requirements of idiom for both interfaces
// (minimal) and hot-reloadable interfaces (allowing creation of registerable
// compile time plugins such as used in database drivers with structs, and the
// end user can then either use interfaces or the provided struct, and both
// options are open.
// This ensures the interface is satisfied for codecer.Codecer and is removed in
// the generated binary because the underscore indicates the value is discarded.
var _ codecer.Codecer = &Codec{}
// Encode implements the codecer.Codecer.Encode by calling the provided
// function, and allows the concrete Codec type to always satisfy the interface,
// while allowing it to be implemented entirely differently.
//
// Note: short functions like this can be one-liners according to gofmt.
func (c *Codec) Encode(input []byte) (string, error) { return c.Encoder(input) }
// Decode implements the codecer.Codecer.Decode by calling the provided
// function, and allows the concrete Codec type to always satisfy the interface,
// while allowing it to be implemented entirely differently.
//
// Note: this also can be a one liner. Since we name the return values in the
// type definition and interface, omitting them here makes the line short enough
// to be a one liner.
func (c *Codec) Decode(input string) ([]byte, error) { return c.Decoder(input) }

View File

@@ -0,0 +1,73 @@
// Package codecer is the interface definition for a Human Readable Binary
// Transcription Codec
//
// Interface definitions should be placed in separate packages to
// implementations so there is no risk of a circular dependency, which is not
// permitted in Go, because this kind of automated interpretation of programmer
// intent is the most expensive thing (time, processing, memory) that compilers
// do.
package codecer
// Codecer is the externally usable interface which provides a check for
// complete implementation as well as illustrating the use of interfaces in Go.
//
// It is an odd name but the idiom for interfaces is to describe it as a <thing
// it does>er - so if the interface is for a print function, it could be called
// Printer, if it finds an average, it could be called Averager, and in this
// case, the interface encodes and decodes, thus 'codec' and the noun forming
// suffix -er. Encoder is useless without a Decoder so neither name really makes
// sense for the interface, and Translator implies linguistic restructuring.
//
// It is helpful to those who must work with your code after or with you to give
// meaningful names, and it is idiomatic in Go programming to make meaningful
// names, so don't be afraid to spend a little time when writing Go code with a
// thesaurus and dictionary. *Especially* if english is not your first language.
// Your colleagues will thank you and the inheritors of your code will be
// grateful that you spent the time.
//
// It may seem somewhat redundant in light of type definition, in the root of
// the repository, which exposes the exact same Encode and Decode functions, but
// the purpose of adding this is that this interface can be implemented without
// using the concrete Codec type above, should the programmer have a need to do
// so.
//
// The implementation only needs to implement these two functions and then
// whatever structure ties it together can be passed around without needing to
// know anything about its internal representations or implementation details.
//
// The purpose of interfaces in Go is exactly to eliminate dependencies on any
// concrete data types so the implementations can be changed without changing
// the consuming code.
//
// We are adding this interface in addition to the use of a struct and closure
// pattern mainly as illustration but also to make sure the student is aware of
// the implicit implementation recognition, the way to make the compile time
// check of implementation, and as an exercise for later, the student can create
// their own implementation by importing this package and use the provided
// implementation, in parallel with their own, or without it, which they can
// implement with an entirely separate and different data structure (which will
// be a struct, most likely, though it can be a slice of interface and be even
// subordinate to another structured variable like a slice of interface, or a
// map of interfaces. Then they can drop this interface in place of the built in
// one and see that they don't have to change the calling code.
//
// Note: though it is not officially recognised as idiomatic, it is the opinion
// of the author of this tutorial that the return values of interface function
// signatures should be named, as it makes no sense to force the developer to
// have to read through the implementation that *idiomatically* should accompany
// an interface, as by idiom, interface should be avoided unless there is more
// than one implementation.
type Codecer interface {
// Encode takes an arbitrary length byte input and returns the output as
// defined for the codec.
Encode(input []byte) (output string, err error)
// Decode takes an encoded string and returns if the encoding is valid and
// the value passes any check function defined for the type.
//
// If the check fails or the input is too short to have a check, false and
// nil is returned. This is the contract for this method that
// implementations should uphold.
Decode(input string) (output []byte, err error)
}

View File

@@ -5,12 +5,14 @@ package pub
import (
"encoding/hex"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
"git-indra.lan/indra-labs/indra"
"git-indra.lan/indra-labs/indra/pkg/b32/based32"
"git-indra.lan/indra-labs/indra/pkg/crypto/key/prv"
log2 "git-indra.lan/indra-labs/indra/pkg/proc/log"
"git-indra.lan/indra-labs/indra/pkg/util/slice"
)
var (
@@ -61,6 +63,22 @@ func (pub *Key) ToHex() (s string, e error) {
return
}
func (pub *Key) ToBase32() (s string) {
b := pub.ToBytes()
bb := append(b[1:], b[0])
var e error
if s, e = based32.Codec.Encode(bb); check(e) {
}
return s
}
func FromBase32(s string) (k *Key, e error) {
var b slice.Bytes
b, e = based32.Codec.Decode(s)
bb := append(b[len(b)-1:], b[:len(b)-1]...)
return FromBytes(bb)
}
func (pb Bytes) Equals(qb Bytes) bool { return pb == qb }
func (pub *Key) ToPublicKey() *secp256k1.PublicKey {

View File

@@ -0,0 +1,27 @@
package pub
import (
"testing"
"git-indra.lan/indra-labs/indra/pkg/crypto/key/prv"
)
func TestBase32(t *testing.T) {
for i := 0; i < 1000; i++ {
var k *prv.Key
var e error
if k, e = prv.GenerateKey(); check(e) {
t.Error(e)
t.FailNow()
}
p := Derive(k)
b32 := p.ToBase32()
log.I.Ln(b32)
var kk *Key
kk, e = FromBase32(b32)
if b32 != kk.ToBase32() {
t.Error(e)
t.FailNow()
}
}
}

View File

@@ -9,8 +9,8 @@ import (
func (eng *Engine) hiddenservice(hs *hiddenservice.Layer, b slice.Bytes,
c *slice.Cursor, prev types.Onion) {
log.D.F("%s adding introduction for key %x", eng.GetLocalNodeAddress(),
hs.Identity.ToBytes())
log.D.F("%s adding introduction for key %s", eng.GetLocalNodeAddress(),
hs.Identity.ToBase32())
eng.Introductions.AddIntro(hs.Identity, b[*c:])
log.I.Ln("stored new introduction, starting broadcast")
go eng.hiddenserviceBroadcaster(hs.Identity)

View File

@@ -9,5 +9,6 @@ import (
func (eng *Engine) intro(intr *intro.Layer, b slice.Bytes,
c *slice.Cursor, prev types.Onion) {
log.D.S(intr)
log.D.F("sending out intro to %s at %s to all known peers",
intr.Key.ToBase32(), intr.AddrPort.String())
}