diff --git a/HIP/hip-15.md b/HIP/hip-15.md index 2a3645824..d784b0a07 100644 --- a/HIP/hip-15.md +++ b/HIP/hip-15.md @@ -73,13 +73,13 @@ d = int array for the digits of a (using 10 to represent "."), so 0.0.123 is [0, h = unsigned byte array containing the ledger ID followed by 6 zero bytes p3 = 26 * 26 * 26 p5 = 26 * 26 * 26 * 26 * 26 -s0 = (d[0] + d[2] + d[4] + d[6] + ...) mod 11 -s1 = (d[1] + d[3] + d[5] + d[7] + ...) mod 11 -s = (...((((d[0] * 31) + d[1]) * 31) + d[2]) * 31 + ... ) * 31 + d[d.length-1]) mod p3 +sd0 = (d[0] + d[2] + d[4] + d[6] + ...) mod 11 +sd1 = (d[1] + d[3] + d[5] + d[7] + ...) mod 11 +sd = (...((((d[0] * 31) + d[1]) * 31) + d[2]) * 31 + ... ) * 31 + d[d.length-1]) mod p3 sh = (...(((h[0] * 31) + h[1]) * 31) + h[2]) * 31 + ... ) * 31 + h[h.length-1]) mod p5 -c = (((d.length mod 5) * 11 + s0) * 11 + s1) * p3 + s + sh ) mod p5 -c = (c * 1000003) % p5 -checksum = c, written as 5 digits in base 26, using a-z +c = (((d.length mod 5) * 11 + sd0) * 11 + sd1) * p3 + sd + sh ) mod p5 +cp = (c * 1000003) % p5 +checksum = cp, written as 5 digits in base 26, using a-z ``` The checksum is a function of the ledger ID, so that the same address will have different checksums if it is on different ledgers. Cryptographically secure ledger IDs will be implemented as part of state proofs. But for now, the following three ledgers will each have a ledger ID consisting of a single byte: @@ -151,10 +151,15 @@ When calculating checksums for all accounts of the form `0.0.x` as `x` counts up ## Reference Implementation -Example code can be downloaded for these languages: +Example code can be downloaded for these languages (the reference implementation is the Java version): +- Pseudocode: [HIP-15-pseudocode.md](https://github.com/hashgraph/hedera-improvement-proposal/assets/hip-15/HIP-15-pseudocode.md) +- Java: [AddressChecksums.java](https://github.com/hashgraph/hedera-improvement-proposal/assets/hip-15/AddressChecksums.java) +- Javascript: [HIP-15-javascript.html](https://github.com/hashgraph/hedera-improvement-proposal/assets/hip-15/HIP-15-javascript.html) +- Spreadsheet: [HIP-15-spreadsheet.xlsx](https://github.com/hashgraph/hedera-improvement-proposal/assets/hip-15/HIP-15-spreadsheet.xlsx) +- Mathematica: [HIP-15-mathematica.nb.txt](https://github.com/hashgraph/hedera-improvement-proposal/assets/hip-15/HIP-15-mathematica.nb.txt) +- All of the above: [HIP-15-all.zip](https://github.com/hashgraph/hedera-improvement-proposal/assets/hip-15/HIP-15-all.zip) + -- [AddressChecksums.java.zip](https://github.com/hashgraph/hedera-improvement-proposal/assets/hip-15/AddressChecksums.java.zip) -- [HIP-15-javascript.html.zip](https://github.com/hashgraph/hedera-improvement-proposal/assets/hip-15/HIP-15-javascript.html.zip) ## Rejected Ideas diff --git a/assets/hip-15/AddressChecksums.java b/assets/hip-15/AddressChecksums.java index 474060d87..2a91931fe 100644 --- a/assets/hip-15/AddressChecksums.java +++ b/assets/hip-15/AddressChecksums.java @@ -102,13 +102,13 @@ public static ParsedAddress parseAddress(byte[] ledgerId, String addr) { * h = unsigned byte array containing the ledger ID followed by 6 zero bytes * p3 = 26 * 26 * 26 * p5 = 26 * 26 * 26 * 26 * 26 - * s0 = (d[0] + d[2] + d[4] + d[6] + ...) mod 11 - * s1 = (d[1] + d[3] + d[5] + d[7] + ...) mod 11 - * s = (...((((d[0] * 31) + d[1]) * 31) + d[2]) * 31 + ... ) * 31 + d[d.length-1]) mod p3 + * sd0 = (d[0] + d[2] + d[4] + d[6] + ...) mod 11 + * sd1 = (d[1] + d[3] + d[5] + d[7] + ...) mod 11 + * sd = (...((((d[0] * 31) + d[1]) * 31) + d[2]) * 31 + ... ) * 31 + d[d.length-1]) mod p3 * sh = (...(((h[0] * 31) + h[1]) * 31) + h[2]) * 31 + ... ) * 31 + h[h.length-1]) mod p5 - * c = (((d.length mod 5) * 11 + s0) * 11 + s1) * p3 + s + sh ) mod p5 - * c = (c * 1000003) mod p5 - * checksum = c, written as 5 digits in base 26, using a-z + * c = (((d.length mod 5) * 11 + sd0) * 11 + sd1) * p3 + sd + sh ) mod p5 + * cp = (c * 1000003) mod p5 + * checksum = cp, written as 5 digits in base 26, using a-z * } * * @param ledgerId @@ -121,11 +121,12 @@ public static String checksum(byte[] ledgerId, String addr) { String a = addr; //address, such as "0.0.123" int[] d = new int[addr.length()]; //digits of address, with 10 for '.', such as [0,10,0,10,1,2,3] byte[] h = ledgerId; //ledger ID as an array of unsigned bytes - int s0 = 0; //sum of even positions (mod 11) - int s1 = 0; //sum of odd positions (mod 11) - int s = 0; //weighted sum of all positions (mod p3) + int sd0 = 0; //sum of even positions (mod 11) + int sd1 = 0; //sum of odd positions (mod 11) + int sd = 0; //weighted sum of all positions (mod p3) int sh = 0; //hash of the ledger ID - long c = 0; //the checksum, as a single number (it's a long, to prevent overflow in c * m) + long c = 0; //the checksum, before the final permutation + long cp = 0; //the checksum, as a single number (it's a long, to prevent overflow) String checksum = ""; //the answer to return final int p3 = 26 * 26 * 26; //3 digits base 26 final int p5 = 26 * 26 * 26 * 26 * 26; //5 digits base 26 @@ -138,11 +139,11 @@ public static String checksum(byte[] ledgerId, String addr) { d[i] = (a.charAt(i) == '.' ? 10 : (a.charAt(i) - ascii_0)); } for (int i = 0; i < d.length; i++) { - s = (w * s + d[i]) % p3; + sd = (w * sd + d[i]) % p3; if (i % 2 == 0) { - s0 = (s0 + d[i]) % 11; + sd0 = (sd0 + d[i]) % 11; } else { - s1 = (s1 + d[i]) % 11; + sd1 = (sd1 + d[i]) % 11; } } for (byte sb : h) { @@ -151,11 +152,11 @@ public static String checksum(byte[] ledgerId, String addr) { for (int i = 0; i < 6; i++) { //process 6 zeros as if they were appended to the ledger ID sh = (w * sh + 0) % p5; } - c = ((((a.length() % 5) * 11 + s0) * 11 + s1) * p3 + s + sh) % p5; - c = (c * m) % p5; + c = ((((a.length() % 5) * 11 + sd0) * 11 + sd1) * p3 + sd + sh) % p5; + cp = (c * m) % p5; for (int i = 0; i < 5; i++) { - checksum = Character.toString(ascii_a + (int)(c % 26)) + checksum; - c /= 26; + checksum = Character.toString(ascii_a + (int)(cp % 26)) + checksum; + cp /= 26; } return checksum; diff --git a/assets/hip-15/AddressChecksums.java.zip b/assets/hip-15/AddressChecksums.java.zip deleted file mode 100644 index 12c3a50e1..000000000 Binary files a/assets/hip-15/AddressChecksums.java.zip and /dev/null differ diff --git a/assets/hip-15/HIP-15-all.zip b/assets/hip-15/HIP-15-all.zip new file mode 100644 index 000000000..84eb07683 Binary files /dev/null and b/assets/hip-15/HIP-15-all.zip differ diff --git a/assets/hip-15/HIP-15-javascript.html b/assets/hip-15/HIP-15-javascript.html index 3df5868f9..32ac7b5b8 100644 --- a/assets/hip-15/HIP-15-javascript.html +++ b/assets/hip-15/HIP-15-javascript.html @@ -46,7 +46,7 @@

HIP-15 Address Checksum Format



-Last updated May 5, 2021. +Last updated May 9, 2021.

(c) 2020-2021 Hedera Hashgraph, released under Apache 2.0 license. @@ -139,23 +139,24 @@

HIP-15 Address Checksum Format

// h = unsigned byte array containing the ledger ID followed by 6 zero bytes // p3 = 26 * 26 * 26 // p5 = 26 * 26 * 26 * 26 * 26 -// s0 = (d[0] + d[2] + d[4] + d[6] + ...) mod 11 -// s1 = (d[1] + d[3] + d[5] + d[7] + ...) mod 11 -// s = (...((((d[0] * 31) + d[1]) * 31) + d[2]) * 31 + ... ) * 31 + d[d.length-1]) mod p3 +// sd0 = (d[0] + d[2] + d[4] + d[6] + ...) mod 11 +// sd1 = (d[1] + d[3] + d[5] + d[7] + ...) mod 11 +// sd = (...((((d[0] * 31) + d[1]) * 31) + d[2]) * 31 + ... ) * 31 + d[d.length-1]) mod p3 // sh = (...(((h[0] * 31) + h[1]) * 31) + h[2]) * 31 + ... ) * 31 + h[h.length-1]) mod p5 -// c = (((d.length mod 5) * 11 + s0) * 11 + s1) * p3 + s + sh ) mod p5 -// c = (c * 1000003) mod p5 -// checksum = c, written as 5 digits in base 26, using a-z +// c = (((d.length mod 5) * 11 + sd0) * 11 + sd1) * p3 + sd + sh ) mod p5 +// cp = (c * 1000003) mod p5 +// checksum = cp, written as 5 digits in base 26, using a-z // //in ports to other languages, answer can be a string, digits an int32[] and the rest int32 (or uint32[] and uint32) function checksum(ledgerId, addr) { let answer = ""; let d = []; //digits with 10 for ".", so if addr == "0.0.123" then d == [0, 10, 0, 10, 1, 2, 3] - let s0 = 0; //sum of even positions (mod 11) - let s1 = 0; //sum of odd positions (mod 11) - let s = 0; //weighted sum of all positions (mod p3) + let sd0 = 0; //sum of even positions (mod 11) + let sd1 = 0; //sum of odd positions (mod 11) + let sd = 0; //weighted sum of all positions (mod p3) let sh = 0; //hash of the ledger ID - let c = 0; //the checksum, as a single number + let c = 0; //the checksum, before the final permutation + let cp = 0; //the checksum, as a single number const p3 = 26 * 26 * 26; //3 digits in base 26 const p5 = 26 * 26 * 26 * 26 * 26; //5 digits in base 26 const ascii_a = "a".charCodeAt(); //97 @@ -171,22 +172,22 @@

HIP-15 Address Checksum Format

d.push(addr[i]=="." ? 10 : parseInt(addr[i],10)); } for (let i=0; i 10 + 48}) - 48; (* "." is 46, "0" is 48 *) + p3 = 26^3; + p5 = 26^5; + sd0 = Mod[Total[d[[1 ;; Length[d] ;; 2]]], 11]; + sd1 = Mod[Total[d[[2 ;; Length[d] ;; 2]]], 11]; + sd = Fold[Mod[#1*31 + #2, p3] &, d]; + sh = Fold[Mod[#1*31 + #2, p5] &, h]; + c = Mod[((Mod[Length[d], 5]*11 + sd0)*11 + sd1)*p3 + sd + sh, p5]; + cp = Mod[c*1000003, p5]; + StringJoin @@ + FromCharacterCode[(IntegerDigits[cp, 26, 5] + + ToCharacterCode["a"][[1]])]]; + +(* Output the given ledger ID and address along with the calculated \ +checksum *) + +output[ledgerId_, address_] := + Print["ledger: ", ledgerId, " address: ", address, "-", + checksum[ledgerId, address]]; + +(* Output checksums for all the examples given in HIP-15 *) + +addresses = {"0.0.1", "0.0.4", "0.0.5", "0.0.6", "0.0.12", "0.0.123", + "0.0.1234567890", "12.345.6789", "1.23.456"}; +output[{0}, #] & /@ addresses; +output[{161, 255, 1}, #] & /@ addresses; + +(* +OUTPUT: +ledger:{0} address:0.0.1-dfkxr +ledger:{0} address:0.0.4-cjcuq +ledger:{0} address:0.0.5-ktach +ledger:{0} address:0.0.6-tcxjy +ledger:{0} address:0.0.12-uuuup +ledger:{0} address:0.0.123-vfmkw +ledger:{0} address:0.0.1234567890-zbhlt +ledger:{0} address:12.345.6789-aoyyt +ledger:{0} address:1.23.456-adpbr +ledger:{161,255,1} address:0.0.1-xzlgq +ledger:{161,255,1} address:0.0.4-xdddp +ledger:{161,255,1} address:0.0.5-fnalg +ledger:{161,255,1} address:0.0.6-nwxsx +ledger:{161,255,1} address:0.0.12-povdo +ledger:{161,255,1} address:0.0.123-pzmtv +ledger:{161,255,1} address:0.0.1234567890-tvhus +ledger:{161,255,1} address:12.345.6789-vizhs +ledger:{161,255,1} address:1.23.456-uxpkq +*) diff --git a/assets/hip-15/HIP-15-pseudocode.md b/assets/hip-15/HIP-15-pseudocode.md new file mode 100644 index 000000000..5d370ee09 --- /dev/null +++ b/assets/hip-15/HIP-15-pseudocode.md @@ -0,0 +1,54 @@ +# HIP-15 Checksum calculation Pseudocode + +The checksum (such as `vfmkw`) is calculated from the no-checksum address (such as `0.0.123` ) by this algorithm: + +``` +a = a valid no-checksum address string, such as 0.0.123 +d = int array for the digits of a (using 10 to represent "."), so 0.0.123 is [0,10,0,10,1,2,3] +h = unsigned byte array containing the ledger ID followed by 6 zero bytes +p3 = 26 * 26 * 26 +p5 = 26 * 26 * 26 * 26 * 26 +sd0 = (d[0] + d[2] + d[4] + d[6] + ...) mod 11 +sd1 = (d[1] + d[3] + d[5] + d[7] + ...) mod 11 +sd = (...((((d[0] * 31) + d[1]) * 31) + d[2]) * 31 + ... ) * 31 + d[d.length-1]) mod p3 +sh = (...(((h[0] * 31) + h[1]) * 31) + h[2]) * 31 + ... ) * 31 + h[h.length-1]) mod p5 +c = (((d.length mod 5) * 11 + sd0) * 11 + sd1) * p3 + sd + sh ) mod p5 +cp = (c * 1000003) % p5 +checksum = cp, written as 5 digits in base 26, using a-z +``` + +Cryptographically secure ledger IDs will be implemented as part of state proofs. But for now, the following three ledgers will each have a ledger ID consisting of a single byte: + +``` +0 = Hedera mainnet +1 = stable testnet +2 = preview net +``` + +Test vectors: + +``` +For ledger ID 0x00: + 0.0.1-dfkxr + 0.0.4-cjcuq + 0.0.5-ktach + 0.0.6-tcxjy + 0.0.12-uuuup + 0.0.123-vfmkw + 0.0.1234567890-zbhlt + 12.345.6789-aoyyt + 1.23.456-adpbr + +For ledger ID 0xa1ff01: + 0.0.1-xzlgq + 0.0.4-xdddp + 0.0.5-fnalg + 0.0.6-nwxsx + 0.0.12-povdo + 0.0.123-pzmtv + 0.0.1234567890-tvhus + 12.345.6789-vizhs + 1.23.456-uxpkq +``` + +(c) 2020-2021 Hedera Hashgraph,released under Apache 2.0 license. diff --git a/assets/hip-15/HIP-15-spreadsheet.xlsx b/assets/hip-15/HIP-15-spreadsheet.xlsx new file mode 100644 index 000000000..0956a063c Binary files /dev/null and b/assets/hip-15/HIP-15-spreadsheet.xlsx differ