# -*- coding: utf-8 -*-
"""
Copyright (c) 2018 beyond-blockchain.org.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import os
import sys
import binascii
import traceback
current_dir = os.path.abspath(os.path.dirname(__file__))
sys.path.append(os.path.join(current_dir, "../.."))
import bbclib
from bbclib.libs.bbclib_config import DEFAULT_CURVETYPE
from bbclib.libs import bbclib_utils, bbclib_error
from bbclib.libs.bbclib_keypair import KeyPair, KeyType
[docs]class BBcSignature:
"""Signature part in a transaction"""
def __init__(self, key_type=DEFAULT_CURVETYPE, unpack=None):
self.key_type = key_type
self.signature = None
self.pubkey = None
self.keypair = None
self.not_initialized = True
if unpack is not None:
self.not_initialized = False
self.unpack(unpack)
[docs] def add(self, signature=None, pubkey=None):
"""Add signature and public key"""
if signature is not None:
self.not_initialized = False
self.signature = signature
if pubkey is not None:
self.pubkey = pubkey
self.keypair = KeyPair(curvetype=self.key_type, pubkey=pubkey)
return True
def __str__(self):
if self.not_initialized:
return " Not initialized\n"
ret = " key_type: %d\n" % self.key_type
ret += " signature: %s\n" % binascii.b2a_hex(self.signature)
if self.pubkey is not None:
ret += " pubkey: %s\n" % binascii.b2a_hex(self.pubkey)
else:
ret += " pubkey: None\n"
return ret
[docs] def pack(self):
"""Pack this object"""
if self.not_initialized:
dat = bytearray(bbclib_utils.to_4byte(KeyType.NOT_INITIALIZED))
return bytes(dat)
dat = bytearray(bbclib_utils.to_4byte(self.key_type))
if self.pubkey is None:
dat.extend(bbclib_utils.to_4byte(0))
else:
pubkey_len_bit = len(self.pubkey) * 8
dat.extend(bbclib_utils.to_4byte(pubkey_len_bit))
dat.extend(self.pubkey)
sig_len_bit = len(self.signature) * 8
dat.extend(bbclib_utils.to_4byte(sig_len_bit))
dat.extend(self.signature)
return bytes(dat)
[docs] def unpack(self, data):
"""Unpack into this object
Args:
data (bytes): packed binary data
Returns:
bool: True if successful
"""
ptr = 0
try:
ptr, self.key_type = bbclib_utils.get_n_byte_int(ptr, 4, data)
if self.key_type == KeyType.NOT_INITIALIZED:
return True
ptr, pubkey_len_bit = bbclib_utils.get_n_byte_int(ptr, 4, data)
if pubkey_len_bit > 0:
pubkey_len = int(pubkey_len_bit/8)
ptr, pubkey = bbclib_utils.get_n_bytes(ptr, pubkey_len, data)
else:
pubkey = None
ptr, sig_len_bit = bbclib_utils.get_n_byte_int(ptr, 4, data)
sig_len = int(sig_len_bit/8)
ptr, signature = bbclib_utils.get_n_bytes(ptr, sig_len, data)
self.add(signature=signature, pubkey=pubkey)
except:
return False
return True
[docs] def verify(self, digest, pubkey=None):
"""Verify digest using pubkey in signature
Args:
digest (bytes): digest to verify
pubkey (bytes): external public key for verification
Returns:
int: 0:invalid, 1:valid
"""
bbclib._reset_error()
if self.keypair is None and pubkey is None:
bbclib._set_error(code=bbclib_error.EBADKEYPAIR, txt="Bad private_key/public_key")
return False
try:
if self.keypair is not None:
flag = self.keypair.verify(digest, self.signature)
else:
keypair = KeyPair(curvetype=self.key_type, pubkey=pubkey)
flag = keypair.verify(digest, self.signature)
except:
traceback.print_exc()
return False
return flag