@@ -4,6 +4,9 @@ import fr.acinq.bitcoin.DeterministicWallet.derivePrivateKey
4
4
import fr.acinq.bitcoin.DeterministicWallet.publicKey
5
5
import kotlin.jvm.JvmStatic
6
6
7
+ /* *
8
+ * Output Script Descriptors: see https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki
9
+ */
7
10
public object Descriptor {
8
11
private fun polyMod (cc : Long , value : Int ): Long {
9
12
var c = cc
@@ -17,35 +20,21 @@ public object Descriptor {
17
20
return c
18
21
}
19
22
23
+ // Taken from: https://github.com/bitcoin/bitcoin/blob/207a22877330709e4462e6092c265ab55c8653ac/src/script/descriptor.cpp
20
24
@JvmStatic
21
25
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
- */
35
26
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"
39
28
40
29
var c = 1L
41
30
var cls = 0
42
31
var clscount = 0
43
32
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
49
38
if (clscount == 3 ) {
50
39
// Emit an extra symbol representing the group numbers, for every 3 characters.
51
40
c = polyMod(c, cls)
@@ -57,11 +46,10 @@ public object Descriptor {
57
46
for (j in 0 until 8 ) c = polyMod(c, 0 ) // Shift further to determine the checksum.
58
47
c = c xor 1 // Prevent appending zeroes from not affecting the checksum.
59
48
60
- var ret = StringBuilder (" " )
49
+ val ret = StringBuilder (" " )
61
50
for (j in 0 until 8 ) {
62
51
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()]
65
53
}
66
54
return ret.toString()
67
55
}
@@ -73,21 +61,17 @@ public object Descriptor {
73
61
}
74
62
75
63
@JvmStatic
76
- public fun BIP84Descriptors (chainHash : ByteVector32 , master : DeterministicWallet .ExtendedPrivateKey ): Pair < String , String > {
64
+ public fun createBIP84Descriptor (chainHash : ByteVector32 , master : DeterministicWallet .ExtendedPrivateKey ): String {
77
65
val (keyPath, _) = getKeyPath(chainHash)
78
66
val accountPub = publicKey(derivePrivateKey(master, KeyPath (keyPath)))
79
67
val fingerprint = DeterministicWallet .fingerprint(master) and 0xFFFFFFFFL
80
- return BIP84Descriptors (chainHash, fingerprint, accountPub)
68
+ return createBIP84Descriptor (chainHash, fingerprint, accountPub)
81
69
}
82
70
83
71
@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 {
85
73
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)} "
92
76
}
93
77
}
0 commit comments