package console import ( "context" "crypto/sha256" "encoding/binary" "errors" "math/bits" "testing" "time" ) // refLeadingZeros is written out independently of keymailpow.go so the // test does not check the code against itself. func refLeadingZeros(h []byte) int { n := 0 for _, b := range h { if b == 0 { n += 8 continue } return n + bits.LeadingZeros8(b) } return n } func refHash(nonce, signPub []byte, counter uint64) []byte { h := sha256.New() h.Write(nonce) h.Write(signPub) var c [8]byte binary.BigEndian.PutUint64(c[:], counter) h.Write(c[:]) return h.Sum(nil) } func TestPowMineFindsAVerifiableCounter(t *testing.T) { nonce := sha256.Sum256([]byte("challenge-token")) signPub := []byte("sign-pub-bytes") ctr, err := powMine(context.Background(), nonce[:], signPub, 12) if err != nil { t.Fatal(err) } if got := refLeadingZeros(refHash(nonce[:], signPub, ctr)); got < 12 { t.Fatalf("counter %d gives %d leading zero bits, want >= 12", ctr, got) } if !powVerify(nonce[:], signPub, ctr, 12) { t.Fatal("powVerify rejects the counter powMine found") } if powVerify(nonce[:], []byte("another key"), ctr, 12) && refLeadingZeros(refHash(nonce[:], []byte("another key"), ctr)) < 12 { t.Fatal("powVerify accepted a solution for a different key") } } func TestPowZeroBitsIsFree(t *testing.T) { if !powVerify(nil, nil, 0, 0) { t.Fatal("0 bits must verify") } ctr, err := powMine(context.Background(), nil, nil, 0) if err != nil || ctr != 0 { t.Fatalf("powMine(0 bits) = %d, %v; want 0, nil", ctr, err) } } func TestPowMineHonoursCancellation(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 20*time.Millisecond) defer cancel() // 64 bits will never be found. _, err := powMine(ctx, []byte("n"), []byte("k"), 64) if !errors.Is(err, context.DeadlineExceeded) { t.Fatalf("powMine under a 20ms deadline = %v, want DeadlineExceeded", err) } }