descriptors.py
1 #!/usr/bin/env python3 2 # Copyright (c) 2019 Pieter Wuille 3 # Distributed under the MIT software license, see the accompanying 4 # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 """Utility functions related to output descriptors""" 6 7 import re 8 9 INPUT_CHARSET = "0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\"\\ " 10 CHECKSUM_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" 11 GENERATOR = [0xf5dee51989, 0xa9fdca3312, 0x1bab10e32d, 0x3706b1677a, 0x644d626ffd] 12 13 def descsum_polymod(symbols): 14 """Internal function that computes the descriptor checksum.""" 15 chk = 1 16 for value in symbols: 17 top = chk >> 35 18 chk = (chk & 0x7ffffffff) << 5 ^ value 19 for i in range(5): 20 chk ^= GENERATOR[i] if ((top >> i) & 1) else 0 21 return chk 22 23 def descsum_expand(s): 24 """Internal function that does the character to symbol expansion""" 25 groups = [] 26 symbols = [] 27 for c in s: 28 if c not in INPUT_CHARSET: 29 return None 30 v = INPUT_CHARSET.find(c) 31 symbols.append(v & 31) 32 groups.append(v >> 5) 33 if len(groups) == 3: 34 symbols.append(groups[0] * 9 + groups[1] * 3 + groups[2]) 35 groups = [] 36 if len(groups) == 1: 37 symbols.append(groups[0]) 38 elif len(groups) == 2: 39 symbols.append(groups[0] * 3 + groups[1]) 40 return symbols 41 42 def descsum_create(s): 43 """Add a checksum to a descriptor without""" 44 symbols = descsum_expand(s) + [0, 0, 0, 0, 0, 0, 0, 0] 45 checksum = descsum_polymod(symbols) ^ 1 46 return s + '#' + ''.join(CHECKSUM_CHARSET[(checksum >> (5 * (7 - i))) & 31] for i in range(8)) 47 48 def descsum_check(s, require=True): 49 """Verify that the checksum is correct in a descriptor""" 50 if '#' not in s: 51 return not require 52 if s[-9] != '#': 53 return False 54 if not all(x in CHECKSUM_CHARSET for x in s[-8:]): 55 return False 56 symbols = descsum_expand(s[:-9]) + [CHECKSUM_CHARSET.find(x) for x in s[-8:]] 57 return descsum_polymod(symbols) == 1 58 59 def drop_origins(s): 60 '''Drop the key origins from a descriptor''' 61 desc = re.sub(r'\[.+?\]', '', s) 62 if '#' in s: 63 desc = desc[:desc.index('#')] 64 return descsum_create(desc)