def to_bytes(self): """TODO""" public_numbers = self.key.public_numbers() key_size = tools.elliptic_curve_key_size(self.network.curve) prefix = SEC1_MAGIC_NOT_COMPRESSED if self.compressed: if public_numbers.y % 2 == 0: prefix = SEC1_MAGIC_COMPRESSED_0 else: prefix = SEC1_MAGIC_COMPRESSED_1 data = bytearray() data.append(prefix) x = encoding.i2b_bigendian(public_numbers.x, key_size) data.extend(x) if not self.compressed: y = encoding.i2b_bigendian(public_numbers.y, key_size) data.extend(y) return bytes(data)
def to_bytes(self): """TODO""" key_size = tools.elliptic_curve_key_size(self.network.curve) exponent = self.key.private_numbers().private_value return encoding.i2b_bigendian(exponent, key_size)
def from_bytes(cls, data, network=network.default, backend=default_backend()): """Create a public key from its raw binary encoding (in SEC1 format). For more info on this format, see: http://www.secg.org/sec1-v2.pdf, section 2.3.4 """ data = bytearray(data) # A public key is a point (x, y) in the elliptic curve, and each # coordinate is represented by a unsigned integer of key_size bytes key_size = tools.elliptic_curve_key_size(network.curve) # The first byte determines whether the key is compressed try: prefix = data.pop(0) except IndexError: raise InvalidEncoding('Invalid key length (buffer is empty)') # If the key is compressed-encoded, only the x coordinate is present compressed = True if len(data) == key_size else False if not compressed and len(data) != 2 * key_size: raise InvalidEncoding('Invalid key length') # The first key_size bytes after the prefix are the x coordinate x = encoding.b2i_bigendian(bytes(data[:key_size])) if compressed: # If the key is compressed, the y coordinate should be computed if prefix == SEC1_MAGIC_COMPRESSED_0: y_parity = 0 elif prefix == SEC1_MAGIC_COMPRESSED_1: y_parity = 1 else: raise InvalidEncoding('Invalid prefix for compressed key') y = tools.ec_public_y_from_x_and_curve(x, y_parity, network.curve) if y is None: raise InvalidPoint() else: # If the key isn't compressed, the last key_size bytes are the y # coordinate if prefix != SEC1_MAGIC_NOT_COMPRESSED: raise InvalidEncoding('Invalid prefix for non-compressed key') y = encoding.b2i_bigendian(bytes(data[key_size:])) return cls.from_point(x, y, network, compressed, backend)
def from_bytes(cls, data, network=network.default, compressed=True, backend=default_backend()): """Create a private key from its raw binary encoding (in SEC1 format). The input buffer should be a zero-padded big endian unsigned integer. For more info on this format, see: http://www.secg.org/sec1-v2.pdf, section 2.3.6 """ if len(data) != tools.elliptic_curve_key_size(network.curve): raise InvalidEncoding('Invalid key length') exponent = encoding.b2i_bigendian(data) try: return cls.from_secret_exponent(exponent, network, compressed, backend) except InvalidExponent as e: raise InvalidEncoding(e.message)
def from_wif(cls, wif, backend=default_backend()): """Create a private key from its WIF encoding. The Wallet Import Format encoding is used for serializing Bitcoin private keys. For more info on this encoding, see: https://en.bitcoin.it/wiki/Wallet_import_format """ # A WIF private key is base58check encoded try: data = bytearray(encoding.a2b_base58check(wif)) except encoding.Error as e: raise InvalidEncoding(e.message) # The first byte determines the network try: prefix = data.pop(0) except IndexError: raise InvalidEncoding('Invalid WIF length') try: network_ = network.Network.get_by_field('wif_prefix', prefix) except network.UnknownNetwork as e: raise InvalidEncoding(e.message) # If the public key should be compressed-encoded, there will be an # extra 1 byte at the end key_size = tools.elliptic_curve_key_size(network_.curve) compressed = True if len(data) == key_size + 1 else False if compressed and data[-1] == 1: data.pop(-1) # What remains should be the raw private key exponent return cls.from_bytes(bytes(data), network_, compressed, backend)