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, "}" | "~") ;
     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 } ;
     Pascal64String     = Pascal64StartChar, { Pascal64Char } ;
     Pascal64Char       = (Digit | Pascal64StartChar)
     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 } ;
     HexString          = HexByte { HexByte } ;
     HexByte            = HexNibble, HexNibble ;
     HexByte            = HexNibble, HexNibble ;
     HexNibble          = ( Digit | "a" | "b" | "c" | "d" | "e" | "f" ) ;       (* no uppercase hex allowed *)
     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 ) ;
     Digit              = ( "0" | NaturalDigit ) ;
     NaturalDigit       = ( "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ) ;
     NaturalDigit       = ( "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ) ;
     EscapeChar         = "\" ;
     EscapeChar         = "\" ;
+```
 
 
 **NOTES**: 
 **NOTES**: 
  * Text payload and passwords are restricted to ANSI charset subset range 32..126
  * 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: **\\**
  * Escape character is always: **\\**
 
 
 The above rules can be interpreted as follows:
 The above rules can be interpreted as follows:
 
 
-```
+
 | Rule               | Interpretation                                                                                                   |
 | Rule               | Interpretation                                                                                                   |
 | -----------------: | :------------------------------------------------------------------------------------------------------------ |
 | -----------------: | :------------------------------------------------------------------------------------------------------------ |
 | EPASA              | This is a layer-2 address, fully backwards compatible as Layer-1 address                                      |
 | 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
 ## 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 
 ### Base Cases 
 
 
 <table>
 <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:
 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
 After matching with the above regex, the named groups need to be extracted and validated as the below snippet shows
 
 
 ```csharp
 ```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
 ```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]. 
 Full source-code for the above is available [here][1].