precis: the nickname profile is not idempotent

Because of the order in which rules are applied for PRECIS profiles,
profiles that use NFKC may not be idempotent. This can lead to
unexpected results when performing comparisons. For example:

'DIAERESIS' (U+00A8) decomposes to 'SPACE' (U+0020) + 'COMBINING
DIAERESIS' (U+0308), but on subsequent applications of the Nickname
profile the Additional Mapping Rule will remove the space.

In future it may be desirable to have a way to tell if a transformer is
idempotent, but for now I have merely noted in the documentation that
some comparisons which one might expect to be true may fail and added a
test.

Change-Id: I4873ecf8ee1e5d21e875c88047b816c6c5150308
Reviewed-on: https://go-review.googlesource.com/40867
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
Run-TryBot: Marcel van Lohuizen <mpvl@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/secure/precis/profile_test.go b/secure/precis/profile_test.go
index 253b2a0..916fc8b 100644
--- a/secure/precis/profile_test.go
+++ b/secure/precis/profile_test.go
@@ -100,6 +100,13 @@
 		{"Å", "å", true},
 		{"ff", "ff", true}, // because of NFKC
 		{"ß", "sS", false},
+
+		// After applying the Nickname profile, \u00a8  becomes \u0020\u0308,
+		// however because the nickname profile is not idempotent, applying it again
+		// to \u0020\u0308 results in \u0308. This behavior is "correct", even if it
+		// is unexpected.
+		{"\u00a8", "\u0020\u0308", false},
+		{"\u0020\u0308", "\u0308", true},
 	}},
 }
 
diff --git a/secure/precis/profiles.go b/secure/precis/profiles.go
index 8b46d50..8601002 100644
--- a/secure/precis/profiles.go
+++ b/secure/precis/profiles.go
@@ -13,10 +13,19 @@
 )
 
 var (
-	Nickname              *Profile = nickname          // Implements the Nickname profile specified in RFC 7700.
-	UsernameCaseMapped    *Profile = usernameCaseMap   // Implements the UsernameCaseMapped profile specified in RFC 7613.
-	UsernameCasePreserved *Profile = usernameNoCaseMap // Implements the UsernameCasePreserved profile specified in RFC 7613.
-	OpaqueString          *Profile = opaquestring      // Implements the OpaqueString profile defined in RFC 7613 for passwords and other secure labels.
+	// Implements the Nickname profile specified in RFC 7700.
+	// The nickname profile is not idempotent and may need to be applied multiple
+	// times before being used for comparisons.
+	Nickname *Profile = nickname
+
+	// Implements the UsernameCaseMapped profile specified in RFC 7613.
+	UsernameCaseMapped *Profile = usernameCaseMap
+
+	// Implements the UsernameCasePreserved profile specified in RFC 7613.
+	UsernameCasePreserved *Profile = usernameNoCaseMap
+
+	// Implements the OpaqueString profile defined in RFC 7613 for passwords and other secure labels.
+	OpaqueString *Profile = opaquestring
 )
 
 var (