Noise Protocol

Lightning Networkでは、メッセージ交換のために、node間のセッションを確立する。このときのやりとりは、その後のprotocolとは異なる。そのために、Noise Protocol Frameworkが利用される。

Noise Protocolは、

Noise is a framework for building crypto protocols. Noise protocols support mutual and optional authentication, identity hiding, forward secrecy, zero round-trip encryption, and other advanced features.

である。WhatsAppでも利用されているプロトコルだ。 golangのパッケージもある。これからセッション確立から実装する。

相手ノードとはIPアドレスなどでTCP接続を行った後、相手をnode_id(Bitcoinの公開鍵と同じ計算で求めた33バイトのデータ)で指定してネゴシエーションを行う。 1.5往復して相手のノードに間違いが無ければ、ネゴシエーションが完了する。

LNDに置いては、brontideというpackageにこれはまとめられていて、下記の要領で接続を実施している。

    // Create a test connection, grabbing either side of the connection
    // into local variables. If the initial crypto handshake fails, then
    // we'll get a non-nil error here.
    localConn, remoteConn, cleanUp, err := establishTestConnection()
    if err != nil {
        t.Fatalf("unable to establish test connection: %v", err)
    }
    defer cleanUp()

    // Test out some message full-message reads.
    for i := 0; i < 10; i++ {
        msg := []byte("hello" + string(i))

        if _, err := localConn.Write(msg); err != nil {
            t.Fatalf("remote conn failed to write: %v", err)
        }

        readBuf := make([]byte, len(msg))
        if _, err := remoteConn.Read(readBuf); err != nil {
            t.Fatalf("local conn failed to read: %v", err)
        }

        if !bytes.Equal(readBuf, msg) {
            t.Fatalf("messages don't match, %v vs %v",
                string(readBuf), string(msg))
        }
    }

    // Now try incremental message reads. This simulates first writing a
    // message header, then a message body.
    outMsg := []byte("hello world")
    if _, err := localConn.Write(outMsg); err != nil {
        t.Fatalf("remote conn failed to write: %v", err)
    }

    readBuf := make([]byte, len(outMsg))
    if _, err := remoteConn.Read(readBuf[:len(outMsg)/2]); err != nil {
        t.Fatalf("local conn failed to read: %v", err)
    }
    if _, err := remoteConn.Read(readBuf[len(outMsg)/2:]); err != nil {
        t.Fatalf("local conn failed to read: %v", err)
    }

    if !bytes.Equal(outMsg, readBuf) {
        t.Fatalf("messages don't match, %v vs %v",
            string(readBuf), string(outMsg))
    }