def decrypt(secret, message): message = message.encode('utf-8') curve = SECP256k1.curve() order = SECP256k1.order() R_size = 1 + 32 mac_size = hashlib.sha256().digest_size message_binary = base64.b64decode(message) if len(message_binary) < (R_size + mac_size): return None R = decode_point(message_binary) d = message_binary[R_size:R_size + mac_size] prefix_bytes = message_binary[R_size + mac_size:R_size + mac_size + 8] c = message_binary[R_size + mac_size + 8:] S = (secret * R).x() S_bytes = S.to_bytes(32, 'big') k_E = hashlib.sha256(S_bytes + b'\0\0\0\1').digest() k_M = hashlib.sha256(S_bytes + b'\0\0\0\2').digest() d_verify = hmac.new(k_M, prefix_bytes + c, hashlib.sha256).digest() if d_verify != d: return None ctr = Counter.new(64, prefix=prefix_bytes) cipher = AES.new(key=k_E, mode=AES.MODE_CTR, counter=ctr) padded = cipher.decrypt(c) try: return unpad(padded, AES.block_size).decode('utf-8') except: return None
def decode_point(p): # See http://www.secg.org/download/aid-780/sec1-v2.pdf section 2.3.4 curve = SECP256k1.curve() order = SECP256k1.order() baselen = 32 if p[0] == 4: # 3 x_str = p[1:baselen + 1] y_str = p[baselen + 1:] return point(int.from_bytes(x_str, 'big'), int.from_bytes(y_str, 'big')) else: # 2.3 if p[0] == 2: yp = 0 elif p[0] == 3: yp = 1 else: return None # 2.2 x_str = p[1:baselen + 1] x = int.from_bytes(x_str, 'big') # 2.4.1 alpha = ((x * x * x) + (curve.a() * x) + curve.b()) % curve.p() beta = pycoin.ecdsa.numbertheory.modular_sqrt(alpha, curve.p()) if (beta - yp) % 2 == 0: y = beta else: y = curve.p() - beta return point(x, y)
def test_inverse_mod(self): prime = generator_secp256k1.curve().p() order = generator_secp256k1.order() for v in range(70): n = int(float("1e%d" % v)) i = inverse_mod(n, prime) assert n * i % prime == 1 i = inverse_mod(n, order) assert n * i % order == 1
def test_key_limits(self): nc = 'BTC' cc = b'000102030405060708090a0b0c0d0e0f' order = generator_secp256k1.order() for k in -1, 0, order, order + 1: self.assertRaises(InvalidSecretExponentError, Key, secret_exponent=k) self.assertRaises(InvalidSecretExponentError, BIP32Node, nc, cc, secret_exponent=k) for i in range(1, 512): Key(secret_exponent=i) BIP32Node(nc, cc, secret_exponent=i)
def sigmake(a_key, a_hash_for_sig, a_sig_type=SIGHASH_ALL): """ Signs a_hash_for_sig with a_key and returns a DER-encoded signature with a_sig_type appended. """ order = generator_secp256k1.order() r, s = ecdsa_sign(generator_secp256k1, a_key.secret_exponent(), a_hash_for_sig) if s + s > order: s = order - s return sigencode_der(r, s) + bytes_from_int(a_sig_type)
def sigmake(a_key, a_hash_for_sig, a_sig_type=SIGHASH_ALL): """ Signs a_hash_for_sig with a_key and returns a DER-encoded signature with a_sig_type appended. """ order = generator_secp256k1.order() r, s = ecdsa_sign(generator_secp256k1, a_key.secret_exponent(), a_hash_for_sig) if s + s > order: s = order - s return sigencode_der(r, s) + int2byte(a_sig_type)
def verify(pubkey, signature, data): """ Verify data is signed by private key. Args: pubkey (str): Hex encoded 33Byte compressed public key signature (str): Hex encoded signature in DER format. Return: bool: True if signature is valid. """ public_pair = encoding.sec_to_public_pair(h2b(pubkey)) val = util.bytestoint(h2b(data)) sig = ecdsa.util.sigdecode_der(h2b(signature), G.order()) return ecdsa_verify(G, public_pair, val, sig)
def sign(privkey, data): """ Sign data with given private key. Args: privkey (str): Hex encoded private key data (str): Hex encoded data to be signed. Return: str: Hex encoded signature in DER format. """ secret_exponent = Key.from_text(privkey_to_wif(privkey)).secret_exponent() e = util.bytestoint(h2b(data)) r, s = ecdsa_sign(G, secret_exponent, e) return b2h(ecdsa.util.sigencode_der(r, s, G.order()))
def encrypt(point, message): message = message.encode('utf-8') padded = pad(message, AES.block_size) r = random.SystemRandom().randint(0, SECP256k1.order()) R = SECP256k1 * r S = (point * r).x() S_bytes = S.to_bytes((S.bit_length() + 7) // 8, 'big') k_E = hashlib.sha256(S_bytes + b'\0\0\0\1').digest() k_M = hashlib.sha256(S_bytes + b'\0\0\0\2').digest() prefix_bytes = random.SystemRandom().getrandbits(64).to_bytes(8, 'little') ctr = Counter.new(64, prefix=prefix_bytes) cipher = AES.new(key=k_E, mode=AES.MODE_CTR, counter=ctr) c = cipher.encrypt(padded) d = hmac.new(k_M, prefix_bytes + c, hashlib.sha256).digest() result = base64.b64encode(encode_point(R, True) + d + prefix_bytes + c).decode('utf-8') return textwrap.fill(result, 40)
def test_special_k(): """ Check that my reworked version of ecdsa.deterministic_generate_k works like the old one, minus my salt. """ import random from pycoin.ecdsa.ecdsa import deterministic_generate_k from pycoin.ecdsa import generator_secp256k1 from pycoin.contrib.msg_signing import deterministic_make_k order = generator_secp256k1.order() r = random.Random(42) saw = set() for i in range(10000): se = r.randint(2, order-2) val = r.randint(0, 2**32) old = deterministic_generate_k(order, se, val) new = deterministic_make_k(order, se, val, trust_no_one=False) assert old == new assert new not in saw saw.add(new)
def test_special_k(): """ Check that my reworked version of ecdsa.deterministic_generate_k works like the old one, minus my salt. """ import random from pycoin.ecdsa.ecdsa import deterministic_generate_k from pycoin.ecdsa import generator_secp256k1 from pycoin.contrib.msg_signing import deterministic_make_k order = generator_secp256k1.order() r = random.Random(42) saw = set() for i in range(10000): se = r.randint(2, order - 2) val = r.randint(0, 2 ** 32) old = deterministic_generate_k(order, se, val) new = deterministic_make_k(order, se, val, trust_no_one=False) assert old == new assert new not in saw saw.add(new)
def dummy_signature(sig_type): order = generator_secp256k1.order() r, s = order - 1, order // 2 return der.sigencode_der(r, s) + bytes_from_int(sig_type)
def signECDSAsecp256k1(msg, privKey): msgHash = sha3_256Hash(msg) signature = sign(generator_secp256k1, privKey, msgHash) return signature def verifyECDSAsecp256k1(msg, signature, pubKey): msgHash = sha3_256Hash(msg) valid = verify(generator_secp256k1, pubKey, msgHash, signature) return valid # assinatura da mensagem utilizando ECDSA utilizando a curva secp256k1 e hash SHA3-256 msg = "Message for ECDSA signing" privKey = secrets.randbelow(generator_secp256k1.order()) signature = signECDSAsecp256k1(msg, privKey) print("Message:", msg) print("Private key:", hex(privKey)) print("Signature: r=" + hex(signature[0]) + ", s=" + hex(signature[1])) # verificando a assinatura utilizando ECDSA utilizando secp256k1 e hash SHA3-256 pubKey = (generator_secp256k1 * privKey).pair() valid = verifyECDSAsecp256k1(msg, signature, pubKey) print("\nMessage:", msg) print("Public key: (" + hex(pubKey[0]) + ", " + hex(pubKey[1]) + ")") print("Signature valid?", valid) # verificando a assinatura utilizando ECDSA utilizando secp256k1 e hash SHA3-256 msg = "Tampered message" valid = verifyECDSAsecp256k1(msg, signature, pubKey)