@@ -4,6 +4,9 @@ import fr.acinq.bitcoin.DeterministicWallet.derivePrivateKey
44import fr.acinq.bitcoin.DeterministicWallet.publicKey
55import kotlin.jvm.JvmStatic
66
7+ /* *
8+ * Output Script Descriptors: see https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki
9+ */
710public object Descriptor {
811 private fun polyMod (cc : Long , value : Int ): Long {
912 var c = cc
@@ -17,35 +20,21 @@ public object Descriptor {
1720 return c
1821 }
1922
23+ // Taken from: https://github.com/bitcoin/bitcoin/blob/207a22877330709e4462e6092c265ab55c8653ac/src/script/descriptor.cpp
2024 @JvmStatic
2125 public fun checksum (span : String ): String {
22- /* * A character set designed such that:
23- * - The most common 'unprotected' descriptor characters (hex, keypaths) are in the first group of 32.
24- * - Case errors cause an offset that's a multiple of 32.
25- * - As many alphabetic characters are in the same group (while following the above restrictions).
26- *
27- * If p(x) gives the position of a character c in this character set, every group of 3 characters
28- * (a,b,c) is encoded as the 4 symbols (p(a) & 31, p(b) & 31, p(c) & 31, (p(a) / 32) + 3 * (p(b) / 32) + 9 * (p(c) / 32).
29- * This means that changes that only affect the lower 5 bits of the position, or only the higher 2 bits, will just
30- * affect a single symbol.
31- *
32- * As a result, within-group-of-32 errors count as 1 symbol, as do cross-group errors that don't affect
33- * the position within the groups.
34- */
3526 val INPUT_CHARSET = " 0123456789()[],'/*abcdefgh@:$%{}" + " IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~" + " ijklmnopqrstuvwxyzABCDEFGH`#\"\\ "
36-
37- /* * The character set for the checksum itself (same as bech32). */
38- val CHECKSUM_CHARSET = " qpzry9x8gf2tvdw0s3jn54khce6mua7l" ;
27+ val CHECKSUM_CHARSET = " qpzry9x8gf2tvdw0s3jn54khce6mua7l"
3928
4029 var c = 1L
4130 var cls = 0
4231 var clscount = 0
4332 span.forEach { ch ->
44- val pos = INPUT_CHARSET .indexOf(ch);
45- if (pos == - 1 ) return " " ;
46- c = polyMod(c, pos and 31 ); // Emit a symbol for the position inside the group, for every character.
47- cls = cls * 3 + (pos shr 5 ); // Accumulate the group numbers
48- clscount = clscount + 1
33+ val pos = INPUT_CHARSET .indexOf(ch)
34+ if (pos == - 1 ) return " "
35+ c = polyMod(c, pos and 31 ) // Emit a symbol for the position inside the group, for every character.
36+ cls = cls * 3 + (pos shr 5 ) // Accumulate the group numbers
37+ clscount + = 1
4938 if (clscount == 3 ) {
5039 // Emit an extra symbol representing the group numbers, for every 3 characters.
5140 c = polyMod(c, cls)
@@ -57,11 +46,10 @@ public object Descriptor {
5746 for (j in 0 until 8 ) c = polyMod(c, 0 ) // Shift further to determine the checksum.
5847 c = c xor 1 // Prevent appending zeroes from not affecting the checksum.
5948
60- var ret = StringBuilder (" " )
49+ val ret = StringBuilder (" " )
6150 for (j in 0 until 8 ) {
6251 val pos1 = (c shr (5 * (7 - j))) and 31
63- val char = CHECKSUM_CHARSET .get(pos1.toInt())
64- ret.set(j, char)
52+ ret[j] = CHECKSUM_CHARSET [pos1.toInt()]
6553 }
6654 return ret.toString()
6755 }
@@ -73,21 +61,17 @@ public object Descriptor {
7361 }
7462
7563 @JvmStatic
76- public fun BIP84Descriptors (chainHash : ByteVector32 , master : DeterministicWallet .ExtendedPrivateKey ): Pair < String , String > {
64+ public fun createBIP84Descriptor (chainHash : ByteVector32 , master : DeterministicWallet .ExtendedPrivateKey ): String {
7765 val (keyPath, _) = getKeyPath(chainHash)
7866 val accountPub = publicKey(derivePrivateKey(master, KeyPath (keyPath)))
7967 val fingerprint = DeterministicWallet .fingerprint(master) and 0xFFFFFFFFL
80- return BIP84Descriptors (chainHash, fingerprint, accountPub)
68+ return createBIP84Descriptor (chainHash, fingerprint, accountPub)
8169 }
8270
8371 @JvmStatic
84- public fun BIP84Descriptors (chainHash : ByteVector32 , fingerprint : Long , accountPub : DeterministicWallet .ExtendedPublicKey ): Pair < String , String > {
72+ public fun createBIP84Descriptor (chainHash : ByteVector32 , fingerprint : Long , accountPub : DeterministicWallet .ExtendedPublicKey ): String {
8573 val (keyPath, prefix) = getKeyPath(chainHash)
86- val accountDesc = " wpkh([${fingerprint.toString(16 )} /$keyPath ]${DeterministicWallet .encode(accountPub, prefix)} /0/*)"
87- val changeDesc = " wpkh([${fingerprint.toString(16 )} /$keyPath ]${DeterministicWallet .encode(accountPub, prefix)} /1/*)"
88- return Pair (
89- " $accountDesc #${checksum(accountDesc)} " ,
90- " $changeDesc #${checksum(changeDesc)} "
91- )
74+ val accountDesc = " wpkh([${fingerprint.toString(16 )} /$keyPath ]${DeterministicWallet .encode(accountPub, prefix)} /<0;1>/*)"
75+ return " $accountDesc #${checksum(accountDesc)} "
9276 }
9377}
0 commit comments