PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/p/moul/x/wesh/v0

Package
Open in gnoweb ↗

Overview

Kind
Pure package
Name
v0
Namespace
moul / x / wesh
Files
12 (README)(gnomod.toml)
Exported functions
n/a — not supported for pure packages by the node (vm/qfuncs)
Module
gno.land/p/moul/x/wesh/v0
gno
0.9

Files (12)

  • README.mdmarkdown
  • gnomod.tomltoml
  • hmac.gnogno
  • link.gnogno
  • rendezvous.gnogno
  • statement.gnogno
  • wesh.gnogno
  • hmac_test.gnogno
  • link_test.gnogno
  • rendezvous_test.gnogno
  • statement_test.gnogno
  • wesh_test.gnogno
  • statement_test.gnogno
    1package wesh23import (4	"encoding/hex"5	"testing"67	"gno.land/p/nt/uassert/v0"8

    Functions

    not supported for pure packages by the node (vm/qfuncs)

    Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.

    )
    9
    10// Fixtures. The signatures were produced with Go's crypto/ed25519 over the
    11// exact statement text this package builds, using the account key whose seed
    12// is 32 x 0x42, the same key as testAccountPKHex.
    13const (
    14 testChainID = "gnoland-1"
    15 testGnoAddr = "g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5"
    16
    17 testDev1Hex = "0707070707070707070707070707070707070707070707070707070707070707"
    18 testDev2Hex = "0909090909090909090909090909090909090909090909090909090909090909"
    19
    20 bindRev1Sig = "4cd53e6096994d2801de1b16cfd1b2d2aa34ff35b265c53fa176cfb18c949be7" +
    21 "0078161fe2afaf503cf808b2f52a321e15a625f56b1b2d0aaaf8c460f6d64702"
    22
    23 dev0Sig = "19d0bd2517ca6308b089196528e6c27359117b80e1972c71c25434a6f260d62a" +
    24 "703a28c2f973d89056e7c691b4f879d38e1b016745508b357d217eb54c984305"
    25 dev0Digest = "003570bf50d50213f9f3e9c76a8271435a8f2e4b7c24010a8e8383dedd0ed2a6"
    26
    27 dev1Sig = "c26b338045373f7504a0d251c2126e31ff3330f08463672a82467daf4dedca51" +
    28 "1da4681715a6c3afe4115622cfcca9ec3f44d5a35f9973c3b9856cc06859810c"
    29 dev1Digest = "35a8219e60f6cd375e1378879de8921f9d554f054cd8a70ea2d3914b20b77bbb"
    30)
    31
    32func TestBindStatementIsCanonical(t *testing.T) {
    33 got := BindStatement(testChainID, testGnoAddr, mustHex(t, testAccountPKHex), mustHex(t, testSeedHex), 1)
    34 want := "gno.wesh/v0:bind\n" + testChainID + "\n" + testGnoAddr + "\n" +
    35 testAccountPKHex + "\n" + testSeedHex + "\n1"
    36 uassert.Equal(t, want, got)
    37}
    38
    39func TestVerifyBind(t *testing.T) {
    40 pk := mustHex(t, testAccountPKHex)
    41 seed := mustHex(t, testSeedHex)
    42 sig := mustHex(t, bindRev1Sig)
    43
    44 uassert.NoError(t, VerifyBind(testChainID, testGnoAddr, pk, seed, 1, sig),
    45 "a signature made by the account key verifies")
    46}
    47
    48// TestVerifyBindRejectsEveryTamperedField is the heart of the scheme: each
    49// field is in the signed text precisely so that changing it invalidates the
    50// signature. One case per field, so a regression names the field it broke.
    51func TestVerifyBindRejectsEveryTamperedField(t *testing.T) {
    52 pk := mustHex(t, testAccountPKHex)
    53 seed := mustHex(t, testSeedHex)
    54 sig := mustHex(t, bindRev1Sig)
    55
    56 cases := []struct {
    57 name string
    58 chainID string
    59 addr string
    60 payload []byte
    61 rev int
    62 }{
    63 {"replayed on another chain", "test7", testGnoAddr, seed, 1},
    64 {"claimed from another gno address", testChainID, "g1manfred47kzduec920z88wfr64ylksmdcedlf5", seed, 1},
    65 {"a different seed swapped in", testChainID, testGnoAddr, repeat(0xEE, 32), 1},
    66 {"an older revision replayed", testChainID, testGnoAddr, seed, 0},
    67 {"a newer revision forged", testChainID, testGnoAddr, seed, 2},
    68 }
    69 for _, tc := range cases {
    70 err := VerifyBind(tc.chainID, tc.addr, pk, tc.payload, tc.rev, sig)
    71 uassert.ErrorIs(t, err, ErrBadSignature, tc.name)
    72 }
    73}
    74
    75func TestVerifyBindRejectsAnotherAccountsKey(t *testing.T) {
    76 err := VerifyBind(testChainID, testGnoAddr, repeat(0x33, 32), mustHex(t, testSeedHex), 1, mustHex(t, bindRev1Sig))
    77 uassert.ErrorIs(t, err, ErrBadSignature)
    78
    79 err = VerifyBind(testChainID, testGnoAddr, repeat(0x33, 31), mustHex(t, testSeedHex), 1, mustHex(t, bindRev1Sig))
    80 uassert.ErrorIs(t, err, ErrBadAccountPKLen)
    81}
    82
    83func TestGenesisDigest(t *testing.T) {
    84 uassert.Equal(t, DigestLen, len(GenesisDigest()))
    85 uassert.Equal(t,
    86 "0000000000000000000000000000000000000000000000000000000000000000",
    87 hex.EncodeToString(GenesisDigest()))
    88}
    89
    90// TestVerifyDeviceChain walks a three-entry sigchain: add, add, revoke. Each
    91// entry chains to the digest of the previous one, which is what stops an entry
    92// being reordered or silently dropped.
    93func TestVerifyDeviceChain(t *testing.T) {
    94 pk := mustHex(t, testAccountPKHex)
    95
    96 d0, err := VerifyDevice(testChainID, pk, 0, GenesisDigest(), OpAdd, mustHex(t, testDev1Hex), mustHex(t, dev0Sig))
    97 uassert.NoError(t, err, "first entry")
    98 uassert.Equal(t, dev0Digest, hex.EncodeToString(d0), "digest the next entry must chain to")
    99
    100 d1, err := VerifyDevice(testChainID, pk, 1, d0, OpAdd, mustHex(t, testDev2Hex), mustHex(t, dev1Sig))
    101 uassert.NoError(t, err, "second entry")
    102 uassert.Equal(t, dev1Digest, hex.EncodeToString(d1))
    103}
    104
    105func TestVerifyDeviceRejectsABrokenChain(t *testing.T) {
    106 pk := mustHex(t, testAccountPKHex)
    107 dev1 := mustHex(t, testDev1Hex)
    108 dev2 := mustHex(t, testDev2Hex)
    109
    110 cases := []struct {
    111 name string
    112 seq int
    113 prev []byte
    114 op string
    115 device []byte
    116 sig string
    117 wantErr error
    118 }{
    119 {"wrong previous digest", 1, GenesisDigest(), OpAdd, dev2, dev1Sig, ErrBadSignature},
    120 {"wrong sequence number", 2, mustHexRaw(dev0Digest), OpAdd, dev2, dev1Sig, ErrBadSignature},
    121 {"operation flipped to revoke", 0, GenesisDigest(), OpRevoke, dev1, dev0Sig, ErrBadSignature},
    122 {"a different device substituted", 0, GenesisDigest(), OpAdd, dev2, dev0Sig, ErrBadSignature},
    123 {"unknown operation", 0, GenesisDigest(), "delete", dev1, dev0Sig, ErrBadOp},
    124 {"negative sequence", -1, GenesisDigest(), OpAdd, dev1, dev0Sig, ErrBadSeq},
    125 {"short previous digest", 0, repeat(0, 31), OpAdd, dev1, dev0Sig, ErrBadPrevLen},
    126 {"short device key", 0, GenesisDigest(), OpAdd, repeat(7, 31), dev0Sig, ErrBadDevicePKLen},
    127 }
    128 for _, tc := range cases {
    129 _, err := VerifyDevice(testChainID, pk, tc.seq, tc.prev, tc.op, tc.device, mustHexRaw(tc.sig))
    130 uassert.ErrorIs(t, err, tc.wantErr, tc.name)
    131 }
    132}
    133
    134func TestValidOp(t *testing.T) {
    135 uassert.True(t, ValidOp(OpAdd))
    136 uassert.True(t, ValidOp(OpRevoke))
    137 uassert.False(t, ValidOp("Add"), "operations are case-sensitive")
    138 uassert.False(t, ValidOp(""))
    139}
    140
    141func mustHexRaw(s string) []byte {
    142 b, err := hex.DecodeString(s)
    143 if err != nil {
    144 panic("bad hex fixture: " + s)
    145 }
    146 return b
    147}
    148