Browse Source

PIP-0027: final edits, bug fixes

Herman Schoenfeld 6 years ago
parent
commit
08a5e18539
1 changed files with 241 additions and 157 deletions
  1. 241 157
      PIP/PIP-0027.md

+ 241 - 157
PIP/PIP-0027.md

@@ -53,13 +53,13 @@ An Extended PASA is defined by the below EBNF grammar:
     ReceiverEncPayload = "(", [ Payload ], ")" ;
     ReceiverEncPayload = "(", [ Payload ], ")" ;
     SenderEncPayload   = "<", [ Payload ], ">" ;
     SenderEncPayload   = "<", [ Payload ], ">" ;
     PasswordEncPayload = "{", [ Payload ], ":", [ Password ], "}" ;
     PasswordEncPayload = "{", [ Payload ], ":", [ Password ], "}" ;
-    Payload            = ( """, SafeAnsiString, """ | "0", "x", HexString | Base58String ) ;
-    Password           = SafeAnsiString
-    SafeAnsiString     = SafeAnsiChar, { SafeAnsiChar } ;
-    SafeAnsiChar       = (" " | "!" | 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     = SafePascal64Char, { Pascal64Char } ;
-    Pascal64Char       = (Digit | SafePascal64Char)
-    SafePascal64Char   = ( "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, ">" | "," | "." | "?" | "/" | "~" ) ; 
+    Payload            = ( """, PascalAsciiString, """ | "0", "x", HexString | Base58String ) ;
+    Password           = PascalAsciiString
+    PascalAsciiString  = PascalAsciiChar, { PascalAsciiChar } ;
+    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, ">" | "," | "." | "?" | "/" | "~" ) ; 
     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 *)
@@ -74,7 +74,7 @@ An Extended PASA is defined by the below EBNF grammar:
 
 
 **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 SafeAnsi strings): **:**, **\\**, **"**, **[**, **]**, **(**, **), **<**, **>**,**{**, **}**
+ * The following characters are escaped in Pascal64 and PascalAscii strings): **:**, **\\**, **"**, **[**, **]**, **(**, **), **<**, **>**,**{**, **}**
  * Escape character is always: **\\**
  * Escape character is always: **\\**
 
 
 The above rules can be interpreted as follows:
 The above rules can be interpreted as follows:
@@ -92,9 +92,9 @@ The above rules can be interpreted as follows:
 | PasswordEncPayload | A payload which is AES256 encrypted using the specified password                                              |
 | PasswordEncPayload | A payload which is AES256 encrypted using the specified password                                              |
 | Payload            | The actual payload data, specified it an well-defined encoding                                                |
 | Payload            | The actual payload data, specified it an well-defined encoding                                                |
 | ExtendedChecksum   | A checksum of all the preceding text in the E-PASA (necessary to prevent typo-errors)                         |
 | ExtendedChecksum   | A checksum of all the preceding text in the E-PASA (necessary to prevent typo-errors)                         |
-| Password           | The password used in PasswordEndPayload. Must be specified as a SafeAnsiString (chars 32..126)                |
+| Password           | The password used in PasswordEndPayload. Must be specified as a PascalAsciiString (chars 32..126)             |
 | Pascal64String     | An ANSI string involving a limited subset used for account names (cannot start with a digit)                  |
 | Pascal64String     | An ANSI string involving a limited subset used for account names (cannot start with a digit)                  |
-| SafeAnsiString     | An ANSI string involvolving subset characters 32..126                                                         |
+| PascalAsciiString  | An ANSI string involvolving subset characters 32..126                                                         |
 | Base58String       | A Base58-encoded string. This is used for specifying public keys, and hashes of public keys                   |
 | Base58String       | A Base58-encoded string. This is used for specifying public keys, and hashes of public keys                   |
 | HexString          | A hexadecimal-encoded string prefixed with a 0x. Every byte specified by two hexdigits, lower-case            |
 | HexString          | A hexadecimal-encoded string prefixed with a 0x. Every byte specified by two hexdigits, lower-case            |
 
 
@@ -372,158 +372,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>[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 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["AccountChecksum"].Success ? match.Groups["AccountChecksum"].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;
-		} else {
-			// Account Number
-			if (!uint.TryParse(accountNumber, out var accNo)) {
-				errorCode = EPasaErrorCode.AccountNumberTooLong;
-				return false;
-			}
-			epasa.PayloadType = epasa.PayloadType ^ PayloadType.AddressedByName;
-			epasa.Account = accNo;
-
-			if (checksumDelim != null) {
-				if (!uint.TryParse(accountChecksum, out var accChecksum)) {
-					errorCode = EPasaErrorCode.AccountChecksumInvalid;
-					return false;
-				}
-				if (!AccountHelper.IsValidAccountChecksum(epasa.Account.Value, accChecksum)) {
-					errorCode = EPasaErrorCode.BadChecksum;
-					return false;
-				}
-				epasa.AccountChecksum = accChecksum;
-			}
-		}
-
-		// 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;
-			} 
-			epasa.Payload = payloadContent;
-		}
-
-		// Payload Lengths
-		if (!EPasaHelper.IsValidPayloadLength(epasa.PayloadType, epasa.Payload)) {
-			errorCode = EPasaErrorCode.PayloadTooLarge;
-			return false;
-		}
-
-		// Extended Checksum
-		if (extendedChecksumDelim != null) {
-			if (checksumDelim == null) {
-				errorCode = EPasaErrorCode.MissingAccountChecksum;
-				return false;
-			}
-			if (!EPasaHelper.IsValidExtendedChecksum(epasa.ToString(true), epasa.ExtendedChecksum)) {
-				errorCode = EPasaErrorCode.BadExtendedChecksum;
-				return false;
-			}
-			epasa.ExtendedChecksum = extendedChecksum;
-		}
-		return true;
-	}
+Some of the referenced methods can be found here:
+
+```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 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;
+        }
 ```
 ```
 
 
 Full source-code for the above is available [here][1]. 
 Full source-code for the above is available [here][1]. 
@@ -536,6 +620,6 @@ A recursive-descent implementation can be found [here][2].
 1. [C# Regex Parser][1]
 1. [C# Regex Parser][1]
 2. [C# Recursive-Descent Parser][2]
 2. [C# Recursive-Descent Parser][2]
 
 
-[1]: https://github.com/Sphere10/NPascalCoin/blob/master/src/NPascalCoin/Common/Parsing/RegexEPasaParser.cs
-[2]: https://github.com/Sphere10/NPascalCoin/blob/master/src/NPascalCoin/Common/Parsing/RecursiveDescentEPasaParser.cs
+[1]: https://github.com/Sphere10/NPascalCoin/blob/master/src/NPascalCoin/Common/Text/RegexEPasaParser.cs
+[2]: https://github.com/Sphere10/NPascalCoin/blob/master/src/NPascalCoin/Common/Text/RecursiveDescentEPasaParser.cs