Browse Source

PIP-0027: final amendments, bug fixes

Herman Schoenfeld 6 years ago
parent
commit
4afe39ea3e
1 changed files with 235 additions and 229 deletions
  1. 235 229
      PIP/PIP-0027.md

+ 235 - 229
PIP/PIP-0027.md

@@ -59,7 +59,7 @@ An Extended PASA is defined by the below EBNF grammar:
     PascalAsciiChar    = (" " | "!" | EscapeChar, """ | "#" | "$" | "%" | "&" | "'" | EscapeChar, "(" | EscapeChar, ")" | "*" | "+" | "," | "-" | "." | "/" | "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | EscapeChar, ":" | ";" | EscapeChar, "<" | "=" | EscapeChar, ">" | "?" | "@" | "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" | EscapeChar, "[" | EscapeChar, "\" | EscapeChar, "]" | "^" | "_" | "`" | "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" | EscapeChar, "{" | "|" | EscapeChar, "}" | "~") ;
     Pascal64String     = Pascal64StartChar, { Pascal64Char } ;
     Pascal64Char       = (Digit | Pascal64StartChar)
-    Pascal64StartChar  = ( "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" | "!" | "@" | "#" | "$" | "%" | "^" | "&" | "*" | EscapeChar, "(" | EscapeChar, ")" | "-" | "+" | EscapeChar, "{" | EscapeChar, "}" | EscapeChar, "[" | EscapeChar, "]" | "_" | EscapeChar, ":" | "`" | "|" | EscapeChar, "<" | EscapeChar, ">" | "," | "." | "?" | "/" | "~" ) ; 
+    Pascal64StartChar  = ( "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" | "!" | "@" | "#" | "$" | "%" | "^" | "&" | "*" | EscapeChar, "(" | EscapeChar, ")" | "-" | "+" | EscapeChar, "{" | EscapeChar, "}" | EscapeChar, "[" | EscapeChar, "]" | "_" | EscapeChar, ":" | EscapeChar, """ | "`" | "|" | EscapeChar, "<" | EscapeChar, ">" | "," | "." | "?" | "/" | "~" ) ; 
     HexString          = HexByte { HexByte } ;
     HexByte            = HexNibble, HexNibble ;
     HexNibble          = ( Digit | "a" | "b" | "c" | "d" | "e" | "f" ) ;       (* no uppercase hex allowed *)
@@ -71,15 +71,17 @@ An Extended PASA is defined by the below EBNF grammar:
     Digit              = ( "0" | NaturalDigit ) ;
     NaturalDigit       = ( "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ) ;
     EscapeChar         = "\" ;
+```
 
 **NOTES**: 
  * Text payload and passwords are restricted to ANSI charset subset range 32..126
- * The following characters are escaped in Pascal64 and PascalAscii strings): **:**, **\\**, **"**, **[**, **]**, **(**, **), **<**, **>**,**{**, **}**
+ * The following characters are escaped in **Pascal64** encoding:  **(** **(** **)** **{** **}** **[** **]** **:** **"** **<** **>**
+ * The following characters are escaped in **PascalAscii** encoding: **"** **(** **)** **:** **<** **>** **[** **\\** **]** **{** **}**
  * Escape character is always: **\\**
 
 The above rules can be interpreted as follows:
 
-```
+
 | Rule               | Interpretation                                                                                                   |
 | -----------------: | :------------------------------------------------------------------------------------------------------------ |
 | EPASA              | This is a layer-2 address, fully backwards compatible as Layer-1 address                                      |
@@ -260,6 +262,10 @@ The values are interpreted as follows:
 
 ## E-PASA Examples
 
+The below cases are only example E-PASA without valid checksums. 
+
+**TODO**: replace with real E-Pasa after implementation QA.
+
 ### Base Cases 
 
 <table>
@@ -372,242 +378,242 @@ For Layer-2 applications the ability for a receiver to auto-decode the E-PASA vi
 
 The following regex parses an e-pasa:
 ```
-((?<AccountNumber>(0|[1-9]\d+))(?:(?<ChecksumDelim>-)(?<Checksum>\d{2}))?|(?<AccountName>(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|!|@|#|\$|%|\^|&|\*|\\\(|\\\)|-|\+|\\\{|\\\}|\\\[|\\]|_|\\:|`|\||\\<|\\>|,|\.|\?|/|~)(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|0|1|2|3|4|5|6|7|8|9|!|@|#|\$|%|\^|&|\*|\\\(|\\\)|-|\+|\\\{|\\\}|\\\[|\\]|_|\\:|`|\||\\<|\\>|,|\.|\?|/|~){2,63}))(?:(?<PayloadStartChar>[\[\(<\{])(?<PayloadContent>"( |!|\\"|#|\$|%|&|'|\\\(|\\\)|\*|\+|,|-|\.|/|0|1|2|3|4|5|6|7|8|9|\\:|;|\\<|=|\\>|\?|@|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|\\\[|\\\\|\\]|\^|_|`|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|\\\{|\||\\\}|~)+"|0x(?:[0-9a-f]{2})+|[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)?(?:(?<PayloadPasswordDelim>:){1}(?<PayloadPassword>( |!|\\"|#|\$|%|&|'|\\\(|\\\)|\*|\+|,|-|\.|/|0|1|2|3|4|5|6|7|8|9|\\:|;|\\<|=|\\>|\?|@|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|\\\[|\\\\|\\]|\^|_|`|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|\\\{|\||\\\}|~)+)?)?(?<PayloadEndChar>[]\)>\}]))?(?:(?<ExtendedChecksumDelim>:)(?<ExtendedChecksum>[0-9a-f]{2}[0-9a-f]{2}))?
+((?<AccountNumber>(0|[1-9]\d+))(?:(?<ChecksumDelim>-)(?<Checksum>\d{2}))?|(?<AccountName>(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|!|@|#|\$|%|\^|&|\*|\\\(|\\\)|-|\+|\\\{|\\\}|\\\[|\\]|_|\\:|\\"|`|\||\\<|\\>|,|\.|\?|/|~)(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|0|1|2|3|4|5|6|7|8|9|!|@|#|\$|%|\^|&|\*|\\\(|\\\)|-|\+|\\\{|\\\}|\\\[|\\]|_|\\:|\\"|`|\||\\<|\\>|,|\.|\?|/|~){2,63}))(?:(?<PayloadStartChar>[\[\(<\{])(?<PayloadContent>"( |!|\\"|#|\$|%|&|'|\\\(|\\\)|\*|\+|,|-|\.|/|0|1|2|3|4|5|6|7|8|9|\\:|;|\\<|=|\\>|\?|@|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|\\\[|\\\\|\\]|\^|_|`|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|\\\{|\||\\\}|~)+"|0x(?:[0-9a-f]{2})+|[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+)?(?:(?<PayloadPasswordDelim>:){1}(?<PayloadPassword>( |!|\\"|#|\$|%|&|'|\\\(|\\\)|\*|\+|,|-|\.|/|0|1|2|3|4|5|6|7|8|9|\\:|;|\\<|=|\\>|\?|@|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|\\\[|\\\\|\\]|\^|_|`|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|\\\{|\||\\\}|~)+)?)?(?<PayloadEndChar>[]\)>\}]))?(?:(?<ExtendedChecksumDelim>:)(?<ExtendedChecksum>[0-9a-f]{2}[0-9a-f]{2}))?
 ```
 
 After matching with the above regex, the named groups need to be extracted and validated as the below snippet shows
 
 ```csharp
-    public override bool TryParse(string epasaText, out EPasa epasa, out EPasaErrorCode errorCode) {
-        errorCode = EPasaErrorCode.Success;
-        epasa = new EPasa();
-
-        if (string.IsNullOrEmpty(epasaText)) {
-            errorCode = EPasaErrorCode.BadFormat;
-            return false;
-        }
-
-        var match = _epasaRegex.Match(epasaText);
-        var checksumDelim = match.Groups["ChecksumDelim"].Success ? match.Groups["ChecksumDelim"].Value : null;
-        var accountNumber = match.Groups["AccountNumber"].Success ? match.Groups["AccountNumber"].Value : null;
-        var accountChecksum = match.Groups["Checksum"].Success ? match.Groups["Checksum"].Value : null;
-        var accountName = match.Groups["AccountName"].Success ? match.Groups["AccountName"].Value : null;
-        var payloadStartChar = match.Groups["PayloadStartChar"].Success ? match.Groups["PayloadStartChar"].Value : null;
-        var payloadEndChar = match.Groups["PayloadEndChar"].Success ? match.Groups["PayloadEndChar"].Value : null;
-        var payloadContent = match.Groups["PayloadContent"].Success ? match.Groups["PayloadContent"].Value : null;
-        var payloadPasswordDelim = match.Groups["PayloadPasswordDelim"].Success ? match.Groups["PayloadPasswordDelim"].Value : null;
-        var payloadPassword = match.Groups["PayloadPassword"].Success ? match.Groups["PayloadPassword"].Value : null;
-        var extendedChecksumDelim = match.Groups["ExtendedChecksumDelim"].Success ? match.Groups["ExtendedChecksumDelim"].Value : null;
-        var extendedChecksum = match.Groups["ExtendedChecksum"].Success ? match.Groups["ExtendedChecksum"].Value : null;
-
-        // Check parsed completely
-        if (epasaText != match.Value) {
-            errorCode = EPasaErrorCode.BadFormat;
-            return false;
-        }
-
-        if (accountName != null) {
-            // Account Name
-            if (string.IsNullOrEmpty(accountName)) {
-                errorCode = EPasaErrorCode.BadFormat;
-                return false;
-            }
-            epasa.PayloadType = epasa.PayloadType | PayloadType.AddressedByName;
-            epasa.AccountName = accountName;
-            epasa.Account = epasa.AccountChecksum = null;
-        } else {
-            // Account Number
-            if (!uint.TryParse(accountNumber, out var accNo)) {
-                errorCode = EPasaErrorCode.InvalidAccountNumber;
-                return false;
-            }
-            epasa.Account = accNo;
-            var actualAccountChecksum = AccountHelper.CalculateAccountChecksum(accNo);
-
-            if (checksumDelim != null) {
-                // validate account checksum
-                if (!uint.TryParse(accountChecksum, out var accChecksum)) {
-                    errorCode = EPasaErrorCode.AccountChecksumInvalid;
-                    return false;
-                }
-                if (accChecksum != actualAccountChecksum) {
-                    errorCode = EPasaErrorCode.BadChecksum;
-                    return false;
-                }
-            }
-            epasa.AccountChecksum = actualAccountChecksum;
-
-        }
-
-        // Encryption type          
-        switch (payloadStartChar) {
-            case null:
-                break;
-            case "[":
-                if (payloadEndChar != "]") {
-                    errorCode = EPasaErrorCode.MismatchedPayloadEncoding;
-                    return false;
-                }
-                epasa.PayloadType = epasa.PayloadType | PayloadType.Public;
-                break;
-            case "(":
-                if (payloadEndChar != ")") {
-                    errorCode = EPasaErrorCode.MismatchedPayloadEncoding;
-                    return false;
-                }
-                epasa.PayloadType = epasa.PayloadType | PayloadType.RecipientKeyEncrypted;
-                break;
-            case "<":
-                if (payloadEndChar != ">") {
-                    errorCode = EPasaErrorCode.MismatchedPayloadEncoding;
-                    return false;
-                }
-                epasa.PayloadType = epasa.PayloadType | PayloadType.SenderKeyEncrypted;
-                break;
-            case "{":
-                if (payloadEndChar != "}") {
-                    errorCode = EPasaErrorCode.MismatchedPayloadEncoding;
-                    return false;
-                }
-                epasa.PayloadType = epasa.PayloadType | PayloadType.PasswordEncrypted;
-                break;
-            default:
-                throw new NotSupportedException($"Unrecognized start character '{payloadStartChar}'");
-
-        }
-
-        // Password
-        if (epasa.PayloadType.HasFlag(PayloadType.PasswordEncrypted)) {
-            if (payloadPasswordDelim == null) {
-                errorCode = EPasaErrorCode.MissingPassword;
-                return false;
-            }
-            epasa.Password = payloadPassword ?? "";
-        } else if (payloadPasswordDelim != null) {
-            errorCode = EPasaErrorCode.UnusedPassword;
-            return false;
-        }
-
-        // Payload 
-        if (payloadStartChar != null) {
-            if (payloadContent == null) {
-                epasa.Payload = string.Empty;
-            } else if (payloadContent.StartsWith("\"")) {
-                epasa.PayloadType = epasa.PayloadType | PayloadType.AsciiFormatted;
-                epasa.Payload = payloadContent.Trim('"');                   
-            } else if (payloadContent.StartsWith("0x")) {
-                epasa.PayloadType = epasa.PayloadType | PayloadType.HexFormatted;
-                epasa.Payload = payloadContent.Substring(2);
-            } else  {
-                epasa.PayloadType = epasa.PayloadType | PayloadType.Base58Formatted;
-                epasa.Payload = payloadContent;
-            } 
-        }
-
-        // Payload Lengths
-        if (!EPasaHelper.IsValidPayloadLength(epasa.PayloadType, epasa.Payload)) {
-            errorCode = EPasaErrorCode.PayloadTooLarge;
-            return false;
-        }
-
-        // Extended Checksum
-        var actualChecksum = EPasaHelper.ComputeExtendedChecksum(epasa.ToString(true));
-        if (extendedChecksumDelim != null) {
-            if (extendedChecksum != actualChecksum) {
-                errorCode = EPasaErrorCode.BadExtendedChecksum;
-                return false;
-            }
-        }
-        epasa.ExtendedChecksum = actualChecksum;
-        return true;
-    }
+public override bool TryParse(string epasaText, out EPasa epasa, out EPasaErrorCode errorCode) {
+	errorCode = EPasaErrorCode.Success;
+	epasa = new EPasa();
+
+	if (string.IsNullOrEmpty(epasaText)) {
+		errorCode = EPasaErrorCode.BadFormat;
+		return false;
+	}
+
+	var match = _epasaRegex.Match(epasaText);
+	var checksumDelim = match.Groups["ChecksumDelim"].Success ? match.Groups["ChecksumDelim"].Value : null;
+	var accountNumber = match.Groups["AccountNumber"].Success ? match.Groups["AccountNumber"].Value : null;
+	var accountChecksum = match.Groups["Checksum"].Success ? match.Groups["Checksum"].Value : null;
+	var accountName = match.Groups["AccountName"].Success ? match.Groups["AccountName"].Value : null;
+	var payloadStartChar = match.Groups["PayloadStartChar"].Success ? match.Groups["PayloadStartChar"].Value : null;
+	var payloadEndChar = match.Groups["PayloadEndChar"].Success ? match.Groups["PayloadEndChar"].Value : null;
+	var payloadContent = match.Groups["PayloadContent"].Success ? match.Groups["PayloadContent"].Value : null;
+	var payloadPasswordDelim = match.Groups["PayloadPasswordDelim"].Success ? match.Groups["PayloadPasswordDelim"].Value : null;
+	var payloadPassword = match.Groups["PayloadPassword"].Success ? match.Groups["PayloadPassword"].Value : null;
+	var extendedChecksumDelim = match.Groups["ExtendedChecksumDelim"].Success ? match.Groups["ExtendedChecksumDelim"].Value : null;
+	var extendedChecksum = match.Groups["ExtendedChecksum"].Success ? match.Groups["ExtendedChecksum"].Value : null;
+
+	// Check parsed completely
+	if (epasaText != match.Value) {
+		errorCode = EPasaErrorCode.BadFormat;
+		return false;
+	}
+
+	if (accountName != null) {
+		// Account Name
+		if (string.IsNullOrEmpty(accountName)) {
+			errorCode = EPasaErrorCode.BadFormat;
+			return false;
+		}
+		epasa.PayloadType = epasa.PayloadType | PayloadType.AddressedByName;
+		epasa.AccountName = Pascal64Encoding.Unescape(accountName);
+		epasa.Account = epasa.AccountChecksum = null;
+	} else {
+		// Account Number
+		if (!uint.TryParse(accountNumber, out var accNo)) {
+			errorCode = EPasaErrorCode.InvalidAccountNumber;
+			return false;
+		}
+		epasa.Account = accNo;
+		var actualAccountChecksum = AccountHelper.CalculateAccountChecksum(accNo);
+
+		if (checksumDelim != null) {
+			// validate account checksum
+			if (!uint.TryParse(accountChecksum, out var accChecksum)) {
+				errorCode = EPasaErrorCode.AccountChecksumInvalid;
+				return false;
+			}
+			if (accChecksum != actualAccountChecksum) {
+				errorCode = EPasaErrorCode.BadChecksum;
+				return false;
+			}
+		}
+		epasa.AccountChecksum = actualAccountChecksum;
+
+	}
+
+	// Encryption type			
+	switch (payloadStartChar) {
+		case null:
+			break;
+		case "[":
+			if (payloadEndChar != "]") {
+				errorCode = EPasaErrorCode.MismatchedPayloadEncoding;
+				return false;
+			}
+			epasa.PayloadType = epasa.PayloadType | PayloadType.Public;
+			break;
+		case "(":
+			if (payloadEndChar != ")") {
+				errorCode = EPasaErrorCode.MismatchedPayloadEncoding;
+				return false;
+			}
+			epasa.PayloadType = epasa.PayloadType | PayloadType.RecipientKeyEncrypted;
+			break;
+		case "<":
+			if (payloadEndChar != ">") {
+				errorCode = EPasaErrorCode.MismatchedPayloadEncoding;
+				return false;
+			}
+			epasa.PayloadType = epasa.PayloadType | PayloadType.SenderKeyEncrypted;
+			break;
+		case "{":
+			if (payloadEndChar != "}") {
+				errorCode = EPasaErrorCode.MismatchedPayloadEncoding;
+				return false;
+			}
+			epasa.PayloadType = epasa.PayloadType | PayloadType.PasswordEncrypted;
+			break;
+		default:
+			throw new NotSupportedException($"Unrecognized start character '{payloadStartChar}'");
+
+	}
+ 
+	// Password
+	if (epasa.PayloadType.HasFlag(PayloadType.PasswordEncrypted)) {
+		if (payloadPasswordDelim == null) {
+			errorCode = EPasaErrorCode.MissingPassword;
+			return false;
+		}
+		epasa.Password = PascalAsciiEncoding.Unescape(payloadPassword ?? "");
+	} else if (payloadPasswordDelim != null) {
+		errorCode = EPasaErrorCode.UnusedPassword;
+		return false;
+	}
+
+	// Payload 
+	if (payloadStartChar != null) {
+		if (payloadContent == null) {
+			epasa.Payload = string.Empty;
+		} else if (payloadContent.StartsWith("\"")) {
+			epasa.PayloadType = epasa.PayloadType | PayloadType.AsciiFormatted;
+			epasa.Payload = PascalAsciiEncoding.Unescape(payloadContent.Trim('"'));
+		} else if (payloadContent.StartsWith("0x")) {
+			epasa.PayloadType = epasa.PayloadType | PayloadType.HexFormatted;
+			epasa.Payload = payloadContent.Substring(2);
+		} else  {
+			epasa.PayloadType = epasa.PayloadType | PayloadType.Base58Formatted;
+			epasa.Payload = payloadContent;
+		} 
+	}
+
+	// Payload Lengths
+	if (!EPasaHelper.IsValidPayloadLength(epasa.PayloadType, epasa.Payload)) {
+		errorCode = EPasaErrorCode.PayloadTooLarge;
+		return false;
+	}
+
+	// Extended Checksum
+	var actualChecksum = EPasaHelper.ComputeExtendedChecksum(epasa.ToString(true));
+	if (extendedChecksumDelim != null) {
+		if (extendedChecksum != actualChecksum) {
+			errorCode = EPasaErrorCode.BadExtendedChecksum;
+			return false;
+		}
+	}
+	epasa.ExtendedChecksum = actualChecksum;
+	return true;
+}
 ```
 
-Some of the referenced methods can be found here:
+Some of the referenced methods can be found below:
 
 ```csharp
+public static byte CalculateAccountChecksum(uint accountNo) {
+	var overflowSafeAccountNo = (ulong) accountNo;
+	return (byte)(overflowSafeAccountNo * 101 % 89 + 10);
+}
+
+public static string ComputeExtendedChecksum(string text) {
+	if (text == null)
+		throw new ArgumentNullException(nameof(text));
+	var checksum = (ushort) (Hashers.MURMUR3_32(Encoding.ASCII.GetBytes(text), ExtendedChecksumMurMur3Seed) % 65536);
+	return EndianBitConverter.Little.GetBytes(checksum).ToHexString(true);
+}
+
+
+public const int MaxPublicAsciiContentLength = 255;
+public const int MaxECIESAsciiContentLength = 144;
+public const int MaxAESAsciiContentLength = 223;
+public const int MaxPublicHexContentLength = 510 + 2;
+public const int MaxECIESHexContentLength = 288 + 2;
+public const int MaxAESHexContentLength = 446 + 2;
+public const int MaxPublicBase58ContentLength = 348;
+public const int MaxECIESBase58ContentLength = 196;
+public const int MaxAESBase58ContentLength = 304;
+public const uint ExtendedChecksumMurMur3Seed = 0;
+
+public static bool IsValidPayloadLength(PayloadType payloadType, string payloadContent) {
+	if (string.IsNullOrEmpty(payloadContent))
+		return true;
+
+	if (payloadType.HasFlag(PayloadType.Public)) {
+		if (payloadType.HasFlag(PayloadType.AsciiFormatted)) {
+			return PascalAsciiEncoding.Unescape(payloadContent).Length <= MaxPublicAsciiContentLength;
+		}
+
+		if (payloadType.HasFlag(PayloadType.HexFormatted)) {
+			return payloadContent.Length <= MaxPublicHexContentLength;
+		}
+
+		if (payloadType.HasFlag(PayloadType.Base58Formatted)) {
+			return payloadContent.Length <= MaxPublicBase58ContentLength;
+		}
+
+		// unknown encoding format
+		return false;
+	}
+
+	if (payloadType.HasFlag(PayloadType.SenderKeyEncrypted) || payloadType.HasFlag(PayloadType.RecipientKeyEncrypted)) {
+		if (payloadType.HasFlag(PayloadType.AsciiFormatted)) {
+			return PascalAsciiEncoding.Unescape(payloadContent).Length <= MaxECIESAsciiContentLength;
+		}
+
+		if (payloadType.HasFlag(PayloadType.HexFormatted)) {
+			return payloadContent.Length <= MaxECIESHexContentLength;
+		}
+
+		if (payloadType.HasFlag(PayloadType.Base58Formatted)) {
+			return payloadContent.Length <= MaxECIESBase58ContentLength;
+		}
+
+		// unknown encoding format
+		return false;
+	}
+
+	if (payloadType.HasFlag(PayloadType.PasswordEncrypted)) {
+		if (payloadType.HasFlag(PayloadType.AsciiFormatted)) {
+			return PascalAsciiEncoding.Unescape(payloadContent).Length <= MaxAESAsciiContentLength;
+		}
+
+		if (payloadType.HasFlag(PayloadType.HexFormatted)) {
+			return payloadContent.Length <= MaxAESHexContentLength;
+		}
+
+		if (payloadType.HasFlag(PayloadType.Base58Formatted)) {
+			return payloadContent.Length <= MaxAESBase58ContentLength;
+		}
+
+		// unknown encoding format
+		return false;
+	}
 
-        public static byte CalculateAccountChecksum(uint accountNo) {
-            var overflowSafeAccountNo = (ulong) accountNo;
-            return (byte)(overflowSafeAccountNo * 101 % 89 + 10);
-        }
-
-        public static string ComputeExtendedChecksum(string text) {
-            if (text == null)
-                throw new ArgumentNullException(nameof(text));
-            var checksum = (ushort) (Hashers.MURMUR3_32(Encoding.ASCII.GetBytes(text), ExtendedChecksumMurMur3Seed) % 65536);
-            return EndianBitConverter.Little.GetBytes(checksum).ToHexString(true);
-        }
-
-        public static bool IsValidPayloadLength(PayloadType payloadType, string payloadContent) {
-            const int MaxPublicAsciiContentLength = 255;
-            const int MaxECIESAsciiContentLength = 144;
-            const int MaxAESAsciiContentLength = 223;
-            const int MaxPublicHexContentLength = 510 + 2;
-            const int MaxECIESHexContentLength = 288 + 2;
-            const int MaxAESHexContentLength = 446 + 2;
-            const int MaxPublicBase58ContentLength = 348;
-            const int MaxECIESBase58ContentLength = 196;
-            const int MaxAESBase58ContentLength = 304;
-            const uint ExtendedChecksumMurMur3Seed = 0;
-
-            if (string.IsNullOrEmpty(payloadContent))
-                return true;
-
-            if (payloadType.HasFlag(PayloadType.Public)) {
-                if (payloadType.HasFlag(PayloadType.AsciiFormatted)) {
-                    return payloadContent.Length <= MaxPublicAsciiContentLength;
-                }
-
-                if (payloadType.HasFlag(PayloadType.HexFormatted)) {
-                    return payloadContent.Length <= MaxPublicHexContentLength;
-                }
-
-                if (payloadType.HasFlag(PayloadType.Base58Formatted)) {
-                    return payloadContent.Length <= MaxPublicBase58ContentLength;
-                }
-
-                // unknown encoding format
-                return false;
-            }
-
-            if (payloadType.HasFlag(PayloadType.SenderKeyEncrypted) || payloadType.HasFlag(PayloadType.RecipientKeyEncrypted)) {
-                if (payloadType.HasFlag(PayloadType.AsciiFormatted)) {
-                    return payloadContent.Length <= MaxECIESAsciiContentLength;
-                }
-
-                if (payloadType.HasFlag(PayloadType.HexFormatted)) {
-                    return payloadContent.Length <= MaxECIESHexContentLength;
-                }
-
-                if (payloadType.HasFlag(PayloadType.Base58Formatted)) {
-                    return payloadContent.Length <= MaxECIESBase58ContentLength;
-                }
-
-                // unknown encoding format
-                return false;
-            }
-
-            if (payloadType.HasFlag(PayloadType.PasswordEncrypted)) {
-                if (payloadType.HasFlag(PayloadType.AsciiFormatted)) {
-                    return payloadContent.Length <= MaxAESAsciiContentLength;
-                }
-
-                if (payloadType.HasFlag(PayloadType.HexFormatted)) {
-                    return payloadContent.Length <= MaxAESHexContentLength;
-                }
-
-                if (payloadType.HasFlag(PayloadType.Base58Formatted)) {
-                    return payloadContent.Length <= MaxAESBase58ContentLength;
-                }
-
-                // unknown encoding format
-                return false;
-            }
-
-            // unknown encryption format
-            return false;
-        }
+	// unknown encryption format
+	return false;
+}
 ```
 
 Full source-code for the above is available [here][1].