|
1 | 1 | package dkls |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "bytes" |
4 | 5 | "crypto/sha256" |
5 | 6 | "testing" |
| 7 | + |
| 8 | + session "go-wrapper/go-dkls/sessions" |
6 | 9 | ) |
7 | 10 |
|
8 | 11 | func TestDeriveKeyID(t *testing.T) { |
@@ -58,3 +61,107 @@ func TestEncodeParticipantIDs(t *testing.T) { |
58 | 61 | }) |
59 | 62 | } |
60 | 63 | } |
| 64 | + |
| 65 | +// The setup blob is what DKLS actually runs on, so these decoders are what let a |
| 66 | +// follower bind it to the values it validated separately. Both must report what |
| 67 | +// the blob really contains, and must error rather than guess on a malformed one. |
| 68 | + |
| 69 | +func TestSetupMessageHash(t *testing.T) { |
| 70 | + participantIDs := encodeParticipantIDs([]string{"party1", "party2"}) |
| 71 | + keyID := make([]byte, 32) |
| 72 | + |
| 73 | + legitHash := make([]byte, 32) |
| 74 | + copy(legitHash, "legitimate-outbound-hash-32bytes") |
| 75 | + attackerHash := make([]byte, 32) |
| 76 | + copy(attackerHash, "attacker-chosen-vault-call-digest") |
| 77 | + |
| 78 | + t.Run("returns the hash embedded in the setup", func(t *testing.T) { |
| 79 | + setup, err := session.DklsSignSetupMsgNew(keyID, nil, legitHash, participantIDs) |
| 80 | + if err != nil { |
| 81 | + t.Fatalf("failed to build sign setup: %v", err) |
| 82 | + } |
| 83 | + got, err := SetupMessageHash(setup) |
| 84 | + if err != nil { |
| 85 | + t.Fatalf("SetupMessageHash() error = %v", err) |
| 86 | + } |
| 87 | + if !bytes.Equal(got, legitHash) { |
| 88 | + t.Errorf("SetupMessageHash() = %x, want %x", got, legitHash) |
| 89 | + } |
| 90 | + }) |
| 91 | + |
| 92 | + // A substituted setup must report the hash it really signs, which is what |
| 93 | + // makes the mismatch detectable. |
| 94 | + t.Run("substituted setup reports the attacker hash", func(t *testing.T) { |
| 95 | + setup, err := session.DklsSignSetupMsgNew(keyID, nil, attackerHash, participantIDs) |
| 96 | + if err != nil { |
| 97 | + t.Fatalf("failed to build sign setup: %v", err) |
| 98 | + } |
| 99 | + got, err := SetupMessageHash(setup) |
| 100 | + if err != nil { |
| 101 | + t.Fatalf("SetupMessageHash() error = %v", err) |
| 102 | + } |
| 103 | + if bytes.Equal(got, legitHash) { |
| 104 | + t.Fatal("substituted setup must not report the legitimate hash") |
| 105 | + } |
| 106 | + if !bytes.Equal(got, attackerHash) { |
| 107 | + t.Errorf("SetupMessageHash() = %x, want %x", got, attackerHash) |
| 108 | + } |
| 109 | + }) |
| 110 | + |
| 111 | + t.Run("errors on empty and malformed setup", func(t *testing.T) { |
| 112 | + if _, err := SetupMessageHash(nil); err == nil { |
| 113 | + t.Error("SetupMessageHash(nil) should error") |
| 114 | + } |
| 115 | + if _, err := SetupMessageHash([]byte("not-a-dkls-setup")); err == nil { |
| 116 | + t.Error("SetupMessageHash(malformed) should error") |
| 117 | + } |
| 118 | + }) |
| 119 | +} |
| 120 | + |
| 121 | +func TestSetupParticipants(t *testing.T) { |
| 122 | + t.Run("returns the participants in index order", func(t *testing.T) { |
| 123 | + want := []string{"alice", "bob", "carol"} |
| 124 | + setup, err := session.DklsKeygenSetupMsgNew(2, nil, encodeParticipantIDs(want)) |
| 125 | + if err != nil { |
| 126 | + t.Fatalf("failed to build keygen setup: %v", err) |
| 127 | + } |
| 128 | + got, err := SetupParticipants(setup) |
| 129 | + if err != nil { |
| 130 | + t.Fatalf("SetupParticipants() error = %v", err) |
| 131 | + } |
| 132 | + if len(got) != len(want) { |
| 133 | + t.Fatalf("SetupParticipants() = %v, want %v", got, want) |
| 134 | + } |
| 135 | + for i := range want { |
| 136 | + if got[i] != want[i] { |
| 137 | + t.Errorf("participant %d = %q, want %q", i, got[i], want[i]) |
| 138 | + } |
| 139 | + } |
| 140 | + }) |
| 141 | + |
| 142 | + // Enumeration terminates on the first empty name rather than an error, which |
| 143 | + // is the contract this relies on to find the end of the list. |
| 144 | + t.Run("terminates at the end of a two party list", func(t *testing.T) { |
| 145 | + want := []string{"first", "second"} |
| 146 | + setup, err := session.DklsKeygenSetupMsgNew(2, nil, encodeParticipantIDs(want)) |
| 147 | + if err != nil { |
| 148 | + t.Fatalf("failed to build keygen setup: %v", err) |
| 149 | + } |
| 150 | + got, err := SetupParticipants(setup) |
| 151 | + if err != nil { |
| 152 | + t.Fatalf("SetupParticipants() error = %v", err) |
| 153 | + } |
| 154 | + if len(got) != 2 || got[0] != "first" || got[1] != "second" { |
| 155 | + t.Errorf("SetupParticipants() = %v, want %v", got, want) |
| 156 | + } |
| 157 | + }) |
| 158 | + |
| 159 | + t.Run("errors on empty and malformed setup", func(t *testing.T) { |
| 160 | + if _, err := SetupParticipants(nil); err == nil { |
| 161 | + t.Error("SetupParticipants(nil) should error") |
| 162 | + } |
| 163 | + if _, err := SetupParticipants([]byte("not-a-dkls-setup")); err == nil { |
| 164 | + t.Error("SetupParticipants(malformed) should error") |
| 165 | + } |
| 166 | + }) |
| 167 | +} |
0 commit comments