electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit ecc11035ecce02c11daf8d79a1d071f49f43df3e
parent 820985dd68e935af353eeabd13b6b34fc7a6e694
Author: Amir Taaki <genjix@riseup.net>
Date:   Wed, 27 Jun 2012 22:18:07 +0200

Merge branch 'master' of gitorious.org:electrum/electrum

Diffstat:
MMANIFEST.in | 2+-
Daes/__init__.py | 656-------------------------------------------------------------------------------
Mblocks | 5++++-
Decdsa/__init__.py | 16----------------
Decdsa/curves.py | 41-----------------------------------------
Decdsa/der.py | 190-------------------------------------------------------------------------------
Decdsa/ecdsa.py | 560-------------------------------------------------------------------------------
Decdsa/ellipticcurve.py | 290-------------------------------------------------------------------------------
Decdsa/keys.py | 252-------------------------------------------------------------------------------
Decdsa/numbertheory.py | 614-------------------------------------------------------------------------------
Decdsa/test_pyecdsa.py | 486-------------------------------------------------------------------------------
Decdsa/util.py | 215-------------------------------------------------------------------------------
Melectrum | 68++++++++++++++++++++++++++++++++++++--------------------------------
Aget_history | 29+++++++++++++++++++++++++++++
Mlib/gui_qt.py | 96++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Mlib/interface.py | 39++++++++++++++++++++++++++++-----------
Mlib/version.py | 4++--
Mlib/wallet.py | 10+++++++++-
Mmki18n.py | 2+-
Mpeers | 1+
Msetup.py | 3++-
Mwatch_address | 1+
22 files changed, 172 insertions(+), 3408 deletions(-)

diff --git a/MANIFEST.in b/MANIFEST.in @@ -8,4 +8,4 @@ include app.fil include icons.qrc include remote.php recursive-include icons * -recursive-include i18n/locale * + diff --git a/aes/__init__.py b/aes/__init__.py @@ -1,656 +0,0 @@ -#!/usr/bin/python -# -# aes.py: implements AES - Advanced Encryption Standard -# from the SlowAES project, http://code.google.com/p/slowaes/ -# -# Copyright (c) 2008 Josh Davis ( http://www.josh-davis.org ), -# Alex Martelli ( http://www.aleax.it ) -# -# Ported from C code written by Laurent Haan ( http://www.progressive-coding.com ) -# -# Licensed under the Apache License, Version 2.0 -# http://www.apache.org/licenses/ -# -import os -import sys -import math - -def append_PKCS7_padding(s): - """return s padded to a multiple of 16-bytes by PKCS7 padding""" - numpads = 16 - (len(s)%16) - return s + numpads*chr(numpads) - -def strip_PKCS7_padding(s): - """return s stripped of PKCS7 padding""" - if len(s)%16 or not s: - raise ValueError("String of len %d can't be PCKS7-padded" % len(s)) - numpads = ord(s[-1]) - if numpads > 16: - raise ValueError("String ending with %r can't be PCKS7-padded" % s[-1]) - return s[:-numpads] - -class AES(object): - # valid key sizes - keySize = dict(SIZE_128=16, SIZE_192=24, SIZE_256=32) - - # Rijndael S-box - sbox = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, - 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, - 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, - 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, - 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, - 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, - 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, - 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, - 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, - 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, - 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, - 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, - 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, - 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, - 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, - 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, - 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, - 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, - 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, - 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, - 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, - 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, - 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, - 0x54, 0xbb, 0x16] - - # Rijndael Inverted S-box - rsbox = [0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, - 0x9e, 0x81, 0xf3, 0xd7, 0xfb , 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, - 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb , 0x54, - 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, - 0x42, 0xfa, 0xc3, 0x4e , 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, - 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 , 0x72, 0xf8, - 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, - 0x65, 0xb6, 0x92 , 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, - 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 , 0x90, 0xd8, 0xab, - 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, - 0x45, 0x06 , 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, - 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b , 0x3a, 0x91, 0x11, 0x41, - 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, - 0x73 , 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, - 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e , 0x47, 0xf1, 0x1a, 0x71, 0x1d, - 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b , - 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, - 0xfe, 0x78, 0xcd, 0x5a, 0xf4 , 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, - 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f , 0x60, - 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, - 0x93, 0xc9, 0x9c, 0xef , 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, - 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 , 0x17, 0x2b, - 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, - 0x21, 0x0c, 0x7d] - - def getSBoxValue(self,num): - """Retrieves a given S-Box Value""" - return self.sbox[num] - - def getSBoxInvert(self,num): - """Retrieves a given Inverted S-Box Value""" - return self.rsbox[num] - - def rotate(self, word): - """ Rijndael's key schedule rotate operation. - - Rotate a word eight bits to the left: eg, rotate(1d2c3a4f) == 2c3a4f1d - Word is an char list of size 4 (32 bits overall). - """ - return word[1:] + word[:1] - - # Rijndael Rcon - Rcon = [0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, - 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, - 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, - 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, - 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, - 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, - 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, - 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, - 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, - 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, - 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, - 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, - 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, - 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, - 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, - 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, - 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, - 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, - 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, - 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, - 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, - 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, - 0xe8, 0xcb ] - - def getRconValue(self, num): - """Retrieves a given Rcon Value""" - return self.Rcon[num] - - def core(self, word, iteration): - """Key schedule core.""" - # rotate the 32-bit word 8 bits to the left - word = self.rotate(word) - # apply S-Box substitution on all 4 parts of the 32-bit word - for i in range(4): - word[i] = self.getSBoxValue(word[i]) - # XOR the output of the rcon operation with i to the first part - # (leftmost) only - word[0] = word[0] ^ self.getRconValue(iteration) - return word - - def expandKey(self, key, size, expandedKeySize): - """Rijndael's key expansion. - - Expands an 128,192,256 key into an 176,208,240 bytes key - - expandedKey is a char list of large enough size, - key is the non-expanded key. - """ - # current expanded keySize, in bytes - currentSize = 0 - rconIteration = 1 - expandedKey = [0] * expandedKeySize - - # set the 16, 24, 32 bytes of the expanded key to the input key - for j in range(size): - expandedKey[j] = key[j] - currentSize += size - - while currentSize < expandedKeySize: - # assign the previous 4 bytes to the temporary value t - t = expandedKey[currentSize-4:currentSize] - - # every 16,24,32 bytes we apply the core schedule to t - # and increment rconIteration afterwards - if currentSize % size == 0: - t = self.core(t, rconIteration) - rconIteration += 1 - # For 256-bit keys, we add an extra sbox to the calculation - if size == self.keySize["SIZE_256"] and ((currentSize % size) == 16): - for l in range(4): t[l] = self.getSBoxValue(t[l]) - - # We XOR t with the four-byte block 16,24,32 bytes before the new - # expanded key. This becomes the next four bytes in the expanded - # key. - for m in range(4): - expandedKey[currentSize] = expandedKey[currentSize - size] ^ \ - t[m] - currentSize += 1 - - return expandedKey - - def addRoundKey(self, state, roundKey): - """Adds (XORs) the round key to the state.""" - for i in range(16): - state[i] ^= roundKey[i] - return state - - def createRoundKey(self, expandedKey, roundKeyPointer): - """Create a round key. - Creates a round key from the given expanded key and the - position within the expanded key. - """ - roundKey = [0] * 16 - for i in range(4): - for j in range(4): - roundKey[j*4+i] = expandedKey[roundKeyPointer + i*4 + j] - return roundKey - - def galois_multiplication(self, a, b): - """Galois multiplication of 8 bit characters a and b.""" - p = 0 - for counter in range(8): - if b & 1: p ^= a - hi_bit_set = a & 0x80 - a <<= 1 - # keep a 8 bit - a &= 0xFF - if hi_bit_set: - a ^= 0x1b - b >>= 1 - return p - - # - # substitute all the values from the state with the value in the SBox - # using the state value as index for the SBox - # - def subBytes(self, state, isInv): - if isInv: getter = self.getSBoxInvert - else: getter = self.getSBoxValue - for i in range(16): state[i] = getter(state[i]) - return state - - # iterate over the 4 rows and call shiftRow() with that row - def shiftRows(self, state, isInv): - for i in range(4): - state = self.shiftRow(state, i*4, i, isInv) - return state - - # each iteration shifts the row to the left by 1 - def shiftRow(self, state, statePointer, nbr, isInv): - for i in range(nbr): - if isInv: - state[statePointer:statePointer+4] = \ - state[statePointer+3:statePointer+4] + \ - state[statePointer:statePointer+3] - else: - state[statePointer:statePointer+4] = \ - state[statePointer+1:statePointer+4] + \ - state[statePointer:statePointer+1] - return state - - # galois multiplication of the 4x4 matrix - def mixColumns(self, state, isInv): - # iterate over the 4 columns - for i in range(4): - # construct one column by slicing over the 4 rows - column = state[i:i+16:4] - # apply the mixColumn on one column - column = self.mixColumn(column, isInv) - # put the values back into the state - state[i:i+16:4] = column - - return state - - # galois multiplication of 1 column of the 4x4 matrix - def mixColumn(self, column, isInv): - if isInv: mult = [14, 9, 13, 11] - else: mult = [2, 1, 1, 3] - cpy = list(column) - g = self.galois_multiplication - - column[0] = g(cpy[0], mult[0]) ^ g(cpy[3], mult[1]) ^ \ - g(cpy[2], mult[2]) ^ g(cpy[1], mult[3]) - column[1] = g(cpy[1], mult[0]) ^ g(cpy[0], mult[1]) ^ \ - g(cpy[3], mult[2]) ^ g(cpy[2], mult[3]) - column[2] = g(cpy[2], mult[0]) ^ g(cpy[1], mult[1]) ^ \ - g(cpy[0], mult[2]) ^ g(cpy[3], mult[3]) - column[3] = g(cpy[3], mult[0]) ^ g(cpy[2], mult[1]) ^ \ - g(cpy[1], mult[2]) ^ g(cpy[0], mult[3]) - return column - - # applies the 4 operations of the forward round in sequence - def aes_round(self, state, roundKey): - state = self.subBytes(state, False) - state = self.shiftRows(state, False) - state = self.mixColumns(state, False) - state = self.addRoundKey(state, roundKey) - return state - - # applies the 4 operations of the inverse round in sequence - def aes_invRound(self, state, roundKey): - state = self.shiftRows(state, True) - state = self.subBytes(state, True) - state = self.addRoundKey(state, roundKey) - state = self.mixColumns(state, True) - return state - - # Perform the initial operations, the standard round, and the final - # operations of the forward aes, creating a round key for each round - def aes_main(self, state, expandedKey, nbrRounds): - state = self.addRoundKey(state, self.createRoundKey(expandedKey, 0)) - i = 1 - while i < nbrRounds: - state = self.aes_round(state, - self.createRoundKey(expandedKey, 16*i)) - i += 1 - state = self.subBytes(state, False) - state = self.shiftRows(state, False) - state = self.addRoundKey(state, - self.createRoundKey(expandedKey, 16*nbrRounds)) - return state - - # Perform the initial operations, the standard round, and the final - # operations of the inverse aes, creating a round key for each round - def aes_invMain(self, state, expandedKey, nbrRounds): - state = self.addRoundKey(state, - self.createRoundKey(expandedKey, 16*nbrRounds)) - i = nbrRounds - 1 - while i > 0: - state = self.aes_invRound(state, - self.createRoundKey(expandedKey, 16*i)) - i -= 1 - state = self.shiftRows(state, True) - state = self.subBytes(state, True) - state = self.addRoundKey(state, self.createRoundKey(expandedKey, 0)) - return state - - # encrypts a 128 bit input block against the given key of size specified - def encrypt(self, iput, key, size): - output = [0] * 16 - # the number of rounds - nbrRounds = 0 - # the 128 bit block to encode - block = [0] * 16 - # set the number of rounds - if size == self.keySize["SIZE_128"]: nbrRounds = 10 - elif size == self.keySize["SIZE_192"]: nbrRounds = 12 - elif size == self.keySize["SIZE_256"]: nbrRounds = 14 - else: return None - - # the expanded keySize - expandedKeySize = 16*(nbrRounds+1) - - # Set the block values, for the block: - # a0,0 a0,1 a0,2 a0,3 - # a1,0 a1,1 a1,2 a1,3 - # a2,0 a2,1 a2,2 a2,3 - # a3,0 a3,1 a3,2 a3,3 - # the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3 - # - # iterate over the columns - for i in range(4): - # iterate over the rows - for j in range(4): - block[(i+(j*4))] = iput[(i*4)+j] - - # expand the key into an 176, 208, 240 bytes key - # the expanded key - expandedKey = self.expandKey(key, size, expandedKeySize) - - # encrypt the block using the expandedKey - block = self.aes_main(block, expandedKey, nbrRounds) - - # unmap the block again into the output - for k in range(4): - # iterate over the rows - for l in range(4): - output[(k*4)+l] = block[(k+(l*4))] - return output - - # decrypts a 128 bit input block against the given key of size specified - def decrypt(self, iput, key, size): - output = [0] * 16 - # the number of rounds - nbrRounds = 0 - # the 128 bit block to decode - block = [0] * 16 - # set the number of rounds - if size == self.keySize["SIZE_128"]: nbrRounds = 10 - elif size == self.keySize["SIZE_192"]: nbrRounds = 12 - elif size == self.keySize["SIZE_256"]: nbrRounds = 14 - else: return None - - # the expanded keySize - expandedKeySize = 16*(nbrRounds+1) - - # Set the block values, for the block: - # a0,0 a0,1 a0,2 a0,3 - # a1,0 a1,1 a1,2 a1,3 - # a2,0 a2,1 a2,2 a2,3 - # a3,0 a3,1 a3,2 a3,3 - # the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3 - - # iterate over the columns - for i in range(4): - # iterate over the rows - for j in range(4): - block[(i+(j*4))] = iput[(i*4)+j] - # expand the key into an 176, 208, 240 bytes key - expandedKey = self.expandKey(key, size, expandedKeySize) - # decrypt the block using the expandedKey - block = self.aes_invMain(block, expandedKey, nbrRounds) - # unmap the block again into the output - for k in range(4): - # iterate over the rows - for l in range(4): - output[(k*4)+l] = block[(k+(l*4))] - return output - - -class AESModeOfOperation(object): - - aes = AES() - - # structure of supported modes of operation - modeOfOperation = dict(OFB=0, CFB=1, CBC=2) - - # converts a 16 character string into a number array - def convertString(self, string, start, end, mode): - if end - start > 16: end = start + 16 - if mode == self.modeOfOperation["CBC"]: ar = [0] * 16 - else: ar = [] - - i = start - j = 0 - while len(ar) < end - start: - ar.append(0) - while i < end: - ar[j] = ord(string[i]) - j += 1 - i += 1 - return ar - - # Mode of Operation Encryption - # stringIn - Input String - # mode - mode of type modeOfOperation - # hexKey - a hex key of the bit length size - # size - the bit length of the key - # hexIV - the 128 bit hex Initilization Vector - def encrypt(self, stringIn, mode, key, size, IV): - if len(key) % size: - return None - if len(IV) % 16: - return None - # the AES input/output - plaintext = [] - iput = [0] * 16 - output = [] - ciphertext = [0] * 16 - # the output cipher string - cipherOut = [] - # char firstRound - firstRound = True - if stringIn != None: - for j in range(int(math.ceil(float(len(stringIn))/16))): - start = j*16 - end = j*16+16 - if end > len(stringIn): - end = len(stringIn) - plaintext = self.convertString(stringIn, start, end, mode) - # print 'PT@%s:%s' % (j, plaintext) - if mode == self.modeOfOperation["CFB"]: - if firstRound: - output = self.aes.encrypt(IV, key, size) - firstRound = False - else: - output = self.aes.encrypt(iput, key, size) - for i in range(16): - if len(plaintext)-1 < i: - ciphertext[i] = 0 ^ output[i] - elif len(output)-1 < i: - ciphertext[i] = plaintext[i] ^ 0 - elif len(plaintext)-1 < i and len(output) < i: - ciphertext[i] = 0 ^ 0 - else: - ciphertext[i] = plaintext[i] ^ output[i] - for k in range(end-start): - cipherOut.append(ciphertext[k]) - iput = ciphertext - elif mode == self.modeOfOperation["OFB"]: - if firstRound: - output = self.aes.encrypt(IV, key, size) - firstRound = False - else: - output = self.aes.encrypt(iput, key, size) - for i in range(16): - if len(plaintext)-1 < i: - ciphertext[i] = 0 ^ output[i] - elif len(output)-1 < i: - ciphertext[i] = plaintext[i] ^ 0 - elif len(plaintext)-1 < i and len(output) < i: - ciphertext[i] = 0 ^ 0 - else: - ciphertext[i] = plaintext[i] ^ output[i] - for k in range(end-start): - cipherOut.append(ciphertext[k]) - iput = output - elif mode == self.modeOfOperation["CBC"]: - for i in range(16): - if firstRound: - iput[i] = plaintext[i] ^ IV[i] - else: - iput[i] = plaintext[i] ^ ciphertext[i] - # print 'IP@%s:%s' % (j, iput) - firstRound = False - ciphertext = self.aes.encrypt(iput, key, size) - # always 16 bytes because of the padding for CBC - for k in range(16): - cipherOut.append(ciphertext[k]) - return mode, len(stringIn), cipherOut - - # Mode of Operation Decryption - # cipherIn - Encrypted String - # originalsize - The unencrypted string length - required for CBC - # mode - mode of type modeOfOperation - # key - a number array of the bit length size - # size - the bit length of the key - # IV - the 128 bit number array Initilization Vector - def decrypt(self, cipherIn, originalsize, mode, key, size, IV): - # cipherIn = unescCtrlChars(cipherIn) - if len(key) % size: - return None - if len(IV) % 16: - return None - # the AES input/output - ciphertext = [] - iput = [] - output = [] - plaintext = [0] * 16 - # the output plain text string - stringOut = '' - # char firstRound - firstRound = True - if cipherIn != None: - for j in range(int(math.ceil(float(len(cipherIn))/16))): - start = j*16 - end = j*16+16 - if j*16+16 > len(cipherIn): - end = len(cipherIn) - ciphertext = cipherIn[start:end] - if mode == self.modeOfOperation["CFB"]: - if firstRound: - output = self.aes.encrypt(IV, key, size) - firstRound = False - else: - output = self.aes.encrypt(iput, key, size) - for i in range(16): - if len(output)-1 < i: - plaintext[i] = 0 ^ ciphertext[i] - elif len(ciphertext)-1 < i: - plaintext[i] = output[i] ^ 0 - elif len(output)-1 < i and len(ciphertext) < i: - plaintext[i] = 0 ^ 0 - else: - plaintext[i] = output[i] ^ ciphertext[i] - for k in range(end-start): - stringOut += chr(plaintext[k]) - iput = ciphertext - elif mode == self.modeOfOperation["OFB"]: - if firstRound: - output = self.aes.encrypt(IV, key, size) - firstRound = False - else: - output = self.aes.encrypt(iput, key, size) - for i in range(16): - if len(output)-1 < i: - plaintext[i] = 0 ^ ciphertext[i] - elif len(ciphertext)-1 < i: - plaintext[i] = output[i] ^ 0 - elif len(output)-1 < i and len(ciphertext) < i: - plaintext[i] = 0 ^ 0 - else: - plaintext[i] = output[i] ^ ciphertext[i] - for k in range(end-start): - stringOut += chr(plaintext[k]) - iput = output - elif mode == self.modeOfOperation["CBC"]: - output = self.aes.decrypt(ciphertext, key, size) - for i in range(16): - if firstRound: - plaintext[i] = IV[i] ^ output[i] - else: - plaintext[i] = iput[i] ^ output[i] - firstRound = False - if originalsize is not None and originalsize < end: - for k in range(originalsize-start): - stringOut += chr(plaintext[k]) - else: - for k in range(end-start): - stringOut += chr(plaintext[k]) - iput = ciphertext - return stringOut - - -def encryptData(key, data, mode=AESModeOfOperation.modeOfOperation["CBC"]): - """encrypt `data` using `key` - - `key` should be a string of bytes. - - returned cipher is a string of bytes prepended with the initialization - vector. - - """ - key = map(ord, key) - if mode == AESModeOfOperation.modeOfOperation["CBC"]: - data = append_PKCS7_padding(data) - keysize = len(key) - assert keysize in AES.keySize.values(), 'invalid key size: %s' % keysize - # create a new iv using random data - iv = [ord(i) for i in os.urandom(16)] - moo = AESModeOfOperation() - (mode, length, ciph) = moo.encrypt(data, mode, key, keysize, iv) - # With padding, the original length does not need to be known. It's a bad - # idea to store the original message length. - # prepend the iv. - return ''.join(map(chr, iv)) + ''.join(map(chr, ciph)) - -def decryptData(key, data, mode=AESModeOfOperation.modeOfOperation["CBC"]): - """decrypt `data` using `key` - - `key` should be a string of bytes. - - `data` should have the initialization vector prepended as a string of - ordinal values. - - """ - - key = map(ord, key) - keysize = len(key) - assert keysize in AES.keySize.values(), 'invalid key size: %s' % keysize - # iv is first 16 bytes - iv = map(ord, data[:16]) - data = map(ord, data[16:]) - moo = AESModeOfOperation() - decr = moo.decrypt(data, None, mode, key, keysize, iv) - if mode == AESModeOfOperation.modeOfOperation["CBC"]: - decr = strip_PKCS7_padding(decr) - return decr - -def generateRandomKey(keysize): - """Generates a key from random data of length `keysize`. - - The returned key is a string of bytes. - - """ - if keysize not in (16, 24, 32): - emsg = 'Invalid keysize, %s. Should be one of (16, 24, 32).' - raise ValueError, emsg % keysize - return os.urandom(keysize) - -if __name__ == "__main__": - moo = AESModeOfOperation() - cleartext = "This is a test!" - cypherkey = [143,194,34,208,145,203,230,143,177,246,97,206,145,92,255,84] - iv = [103,35,148,239,76,213,47,118,255,222,123,176,106,134,98,92] - mode, orig_len, ciph = moo.encrypt(cleartext, moo.modeOfOperation["CBC"], - cypherkey, moo.aes.keySize["SIZE_128"], iv) - print 'm=%s, ol=%s (%s), ciph=%s' % (mode, orig_len, len(cleartext), ciph) - decr = moo.decrypt(ciph, orig_len, mode, cypherkey, - moo.aes.keySize["SIZE_128"], iv) - print decr diff --git a/blocks b/blocks @@ -8,6 +8,9 @@ i.start() i.send([('blockchain.numblocks.subscribe',[])]) while True: - r = i.responses.get(True, 100000000000) + try: + r = i.responses.get(True, 100000000000) + except KeyboardInterrupt: + break if r.get('method') == 'blockchain.numblocks.subscribe': print r.get('result') diff --git a/ecdsa/__init__.py b/ecdsa/__init__.py @@ -1,16 +0,0 @@ - -from keys import SigningKey, VerifyingKey, BadSignatureError, BadDigestError -from curves import NIST192p, NIST224p, NIST256p, NIST384p, NIST521p - -_hush_pyflakes = [SigningKey, VerifyingKey, BadSignatureError, BadDigestError, - NIST192p, NIST224p, NIST256p, NIST384p, NIST521p] -del _hush_pyflakes - -# This code comes from http://github.com/warner/python-ecdsa - -try: - from _version import __version__ as v - __version__ = v - del v -except ImportError: - __version__ = "UNKNOWN" diff --git a/ecdsa/curves.py b/ecdsa/curves.py @@ -1,41 +0,0 @@ -import der, ecdsa - -class UnknownCurveError(Exception): - pass - -def orderlen(order): - return (1+len("%x"%order))//2 # bytes - -# the NIST curves -class Curve: - def __init__(self, name, curve, generator, oid): - self.name = name - self.curve = curve - self.generator = generator - self.order = generator.order() - self.baselen = orderlen(self.order) - self.verifying_key_length = 2*self.baselen - self.signature_length = 2*self.baselen - self.oid = oid - self.encoded_oid = der.encode_oid(*oid) - -NIST192p = Curve("NIST192p", ecdsa.curve_192, ecdsa.generator_192, - (1, 2, 840, 10045, 3, 1, 1)) -NIST224p = Curve("NIST224p", ecdsa.curve_224, ecdsa.generator_224, - (1, 3, 132, 0, 33)) -NIST256p = Curve("NIST256p", ecdsa.curve_256, ecdsa.generator_256, - (1, 2, 840, 10045, 3, 1, 7)) -NIST384p = Curve("NIST384p", ecdsa.curve_384, ecdsa.generator_384, - (1, 3, 132, 0, 34)) -NIST521p = Curve("NIST521p", ecdsa.curve_521, ecdsa.generator_521, - (1, 3, 132, 0, 35)) - -curves = [NIST192p, NIST224p, NIST256p, NIST384p, NIST521p] - -def find_curve(oid_curve): - for c in curves: - if c.oid == oid_curve: - return c - raise UnknownCurveError("I don't know about the curve with oid %s." - "I only know about these: %s" % - (oid_curve, [c.name for c in curves])) diff --git a/ecdsa/der.py b/ecdsa/der.py @@ -1,190 +0,0 @@ -import binascii -import base64 - -class UnexpectedDER(Exception): - pass - -def encode_constructed(tag, value): - return chr(0xa0+tag) + encode_length(len(value)) + value -def encode_integer(r): - assert r >= 0 # can't support negative numbers yet - h = "%x" % r - if len(h)%2: - h = "0" + h - s = binascii.unhexlify(h) - if ord(s[0]) <= 0x7f: - return "\x02" + chr(len(s)) + s - else: - # DER integers are two's complement, so if the first byte is - # 0x80-0xff then we need an extra 0x00 byte to prevent it from - # looking negative. - return "\x02" + chr(len(s)+1) + "\x00" + s - -def encode_bitstring(s): - return "\x03" + encode_length(len(s)) + s -def encode_octet_string(s): - return "\x04" + encode_length(len(s)) + s -def encode_oid(first, second, *pieces): - assert first <= 2 - assert second <= 39 - encoded_pieces = [chr(40*first+second)] + [encode_number(p) - for p in pieces] - body = "".join(encoded_pieces) - return "\x06" + encode_length(len(body)) + body -def encode_sequence(*encoded_pieces): - total_len = sum([len(p) for p in encoded_pieces]) - return "\x30" + encode_length(total_len) + "".join(encoded_pieces) -def encode_number(n): - b128_digits = [] - while n: - b128_digits.insert(0, (n & 0x7f) | 0x80) - n = n >> 7 - if not b128_digits: - b128_digits.append(0) - b128_digits[-1] &= 0x7f - return "".join([chr(d) for d in b128_digits]) - -def remove_constructed(string): - s0 = ord(string[0]) - if (s0 & 0xe0) != 0xa0: - raise UnexpectedDER("wanted constructed tag (0xa0-0xbf), got 0x%02x" - % s0) - tag = s0 & 0x1f - length, llen = read_length(string[1:]) - body = string[1+llen:1+llen+length] - rest = string[1+llen+length:] - return tag, body, rest - -def remove_sequence(string): - if not string.startswith("\x30"): - raise UnexpectedDER("wanted sequence (0x30), got 0x%02x" % - ord(string[0])) - length, lengthlength = read_length(string[1:]) - endseq = 1+lengthlength+length - return string[1+lengthlength:endseq], string[endseq:] - -def remove_octet_string(string): - if not string.startswith("\x04"): - raise UnexpectedDER("wanted octetstring (0x04), got 0x%02x" % - ord(string[0])) - length, llen = read_length(string[1:]) - body = string[1+llen:1+llen+length] - rest = string[1+llen+length:] - return body, rest - -def remove_object(string): - if not string.startswith("\x06"): - raise UnexpectedDER("wanted object (0x06), got 0x%02x" % - ord(string[0])) - length, lengthlength = read_length(string[1:]) - body = string[1+lengthlength:1+lengthlength+length] - rest = string[1+lengthlength+length:] - numbers = [] - while body: - n, ll = read_number(body) - numbers.append(n) - body = body[ll:] - n0 = numbers.pop(0) - first = n0//40 - second = n0-(40*first) - numbers.insert(0, first) - numbers.insert(1, second) - return tuple(numbers), rest - -def remove_integer(string): - if not string.startswith("\x02"): - raise UnexpectedDER("wanted integer (0x02), got 0x%02x" % - ord(string[0])) - length, llen = read_length(string[1:]) - numberbytes = string[1+llen:1+llen+length] - rest = string[1+llen+length:] - assert ord(numberbytes[0]) < 0x80 # can't support negative numbers yet - return int(binascii.hexlify(numberbytes), 16), rest - -def read_number(string): - number = 0 - llen = 0 - # base-128 big endian, with b7 set in all but the last byte - while True: - if llen > len(string): - raise UnexpectedDER("ran out of length bytes") - number = number << 7 - d = ord(string[llen]) - number += (d & 0x7f) - llen += 1 - if not d & 0x80: - break - return number, llen - -def encode_length(l): - assert l >= 0 - if l < 0x80: - return chr(l) - s = "%x" % l - if len(s)%2: - s = "0"+s - s = binascii.unhexlify(s) - llen = len(s) - return chr(0x80|llen) + s - -def read_length(string): - if not (ord(string[0]) & 0x80): - # short form - return (ord(string[0]) & 0x7f), 1 - # else long-form: b0&0x7f is number of additional base256 length bytes, - # big-endian - llen = ord(string[0]) & 0x7f - if llen > len(string)-1: - raise UnexpectedDER("ran out of length bytes") - return int(binascii.hexlify(string[1:1+llen]), 16), 1+llen - -def remove_bitstring(string): - if not string.startswith("\x03"): - raise UnexpectedDER("wanted bitstring (0x03), got 0x%02x" % - ord(string[0])) - length, llen = read_length(string[1:]) - body = string[1+llen:1+llen+length] - rest = string[1+llen+length:] - return body, rest - -# SEQUENCE([1, STRING(secexp), cont[0], OBJECT(curvename), cont[1], BINTSTRING) - - -# signatures: (from RFC3279) -# ansi-X9-62 OBJECT IDENTIFIER ::= { -# iso(1) member-body(2) us(840) 10045 } -# -# id-ecSigType OBJECT IDENTIFIER ::= { -# ansi-X9-62 signatures(4) } -# ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { -# id-ecSigType 1 } -## so 1,2,840,10045,4,1 -## so 0x42, .. .. - -# Ecdsa-Sig-Value ::= SEQUENCE { -# r INTEGER, -# s INTEGER } - -# id-public-key-type OBJECT IDENTIFIER ::= { ansi-X9.62 2 } -# -# id-ecPublicKey OBJECT IDENTIFIER ::= { id-publicKeyType 1 } - -# I think the secp224r1 identifier is (t=06,l=05,v=2b81040021) -# secp224r1 OBJECT IDENTIFIER ::= { -# iso(1) identified-organization(3) certicom(132) curve(0) 33 } -# and the secp384r1 is (t=06,l=05,v=2b81040022) -# secp384r1 OBJECT IDENTIFIER ::= { -# iso(1) identified-organization(3) certicom(132) curve(0) 34 } - -def unpem(pem): - d = "".join([l.strip() for l in pem.split("\n") - if l and not l.startswith("-----")]) - return base64.b64decode(d) -def topem(der, name): - b64 = base64.b64encode(der) - lines = ["-----BEGIN %s-----\n" % name] - lines.extend([b64[start:start+64]+"\n" - for start in range(0, len(b64), 64)]) - lines.append("-----END %s-----\n" % name) - return "".join(lines) - diff --git a/ecdsa/ecdsa.py b/ecdsa/ecdsa.py @@ -1,560 +0,0 @@ -#! /usr/bin/env python -""" -Implementation of Elliptic-Curve Digital Signatures. - -Classes and methods for elliptic-curve signatures: -private keys, public keys, signatures, -NIST prime-modulus curves with modulus lengths of -192, 224, 256, 384, and 521 bits. - -Example: - - # (In real-life applications, you would probably want to - # protect against defects in SystemRandom.) - from random import SystemRandom - randrange = SystemRandom().randrange - - # Generate a public/private key pair using the NIST Curve P-192: - - g = generator_192 - n = g.order() - secret = randrange( 1, n ) - pubkey = Public_key( g, g * secret ) - privkey = Private_key( pubkey, secret ) - - # Signing a hash value: - - hash = randrange( 1, n ) - signature = privkey.sign( hash, randrange( 1, n ) ) - - # Verifying a signature for a hash value: - - if pubkey.verifies( hash, signature ): - print "Demo verification succeeded." - else: - print "*** Demo verification failed." - - # Verification fails if the hash value is modified: - - if pubkey.verifies( hash-1, signature ): - print "**** Demo verification failed to reject tampered hash." - else: - print "Demo verification correctly rejected tampered hash." - -Version of 2009.05.16. - -Revision history: - 2005.12.31 - Initial version. - 2008.11.25 - Substantial revisions introducing new classes. - 2009.05.16 - Warn against using random.randrange in real applications. - 2009.05.17 - Use random.SystemRandom by default. - -Written in 2005 by Peter Pearson and placed in the public domain. -""" - - -import ellipticcurve -import numbertheory -import random - - - -class Signature( object ): - """ECDSA signature. - """ - def __init__( self, r, s ): - self.r = r - self.s = s - - - -class Public_key( object ): - """Public key for ECDSA. - """ - - def __init__( self, generator, point ): - """generator is the Point that generates the group, - point is the Point that defines the public key. - """ - - self.curve = generator.curve() - self.generator = generator - self.point = point - n = generator.order() - if not n: - raise RuntimeError, "Generator point must have order." - if not n * point == ellipticcurve.INFINITY: - raise RuntimeError, "Generator point order is bad." - if point.x() < 0 or n <= point.x() or point.y() < 0 or n <= point.y(): - raise RuntimeError, "Generator point has x or y out of range." - - - def verifies( self, hash, signature ): - """Verify that signature is a valid signature of hash. - Return True if the signature is valid. - """ - - # From X9.62 J.3.1. - - G = self.generator - n = G.order() - r = signature.r - s = signature.s - if r < 1 or r > n-1: return False - if s < 1 or s > n-1: return False - c = numbertheory.inverse_mod( s, n ) - u1 = ( hash * c ) % n - u2 = ( r * c ) % n - xy = u1 * G + u2 * self.point - v = xy.x() % n - return v == r - - - -class Private_key( object ): - """Private key for ECDSA. - """ - - def __init__( self, public_key, secret_multiplier ): - """public_key is of class Public_key; - secret_multiplier is a large integer. - """ - - self.public_key = public_key - self.secret_multiplier = secret_multiplier - - def sign( self, hash, random_k ): - """Return a signature for the provided hash, using the provided - random nonce. It is absolutely vital that random_k be an unpredictable - number in the range [1, self.public_key.point.order()-1]. If - an attacker can guess random_k, he can compute our private key from a - single signature. Also, if an attacker knows a few high-order - bits (or a few low-order bits) of random_k, he can compute our private - key from many signatures. The generation of nonces with adequate - cryptographic strength is very difficult and far beyond the scope - of this comment. - - May raise RuntimeError, in which case retrying with a new - random value k is in order. - """ - - G = self.public_key.generator - n = G.order() - k = random_k % n - p1 = k * G - r = p1.x() - if r == 0: raise RuntimeError, "amazingly unlucky random number r" - s = ( numbertheory.inverse_mod( k, n ) * \ - ( hash + ( self.secret_multiplier * r ) % n ) ) % n - if s == 0: raise RuntimeError, "amazingly unlucky random number s" - return Signature( r, s ) - - - -def int_to_string( x ): - """Convert integer x into a string of bytes, as per X9.62.""" - assert x >= 0 - if x == 0: return chr(0) - result = "" - while x > 0: - q, r = divmod( x, 256 ) - result = chr( r ) + result - x = q - return result - - -def string_to_int( s ): - """Convert a string of bytes into an integer, as per X9.62.""" - result = 0L - for c in s: result = 256 * result + ord( c ) - return result - - -def digest_integer( m ): - """Convert an integer into a string of bytes, compute - its SHA-1 hash, and convert the result to an integer.""" - # - # I don't expect this function to be used much. I wrote - # it in order to be able to duplicate the examples - # in ECDSAVS. - # - from hashlib import sha1 - return string_to_int( sha1( int_to_string( m ) ).digest() ) - - -def point_is_valid( generator, x, y ): - """Is (x,y) a valid public key based on the specified generator?""" - - # These are the tests specified in X9.62. - - n = generator.order() - curve = generator.curve() - if x < 0 or n <= x or y < 0 or n <= y: - return False - if not curve.contains_point( x, y ): - return False - if not n*ellipticcurve.Point( curve, x, y ) == \ - ellipticcurve.INFINITY: - return False - return True - - - -# NIST Curve P-192: -_p = 6277101735386680763835789423207666416083908700390324961279L -_r = 6277101735386680763835789423176059013767194773182842284081L -# s = 0x3045ae6fc8422f64ed579528d38120eae12196d5L -# c = 0x3099d2bbbfcb2538542dcd5fb078b6ef5f3d6fe2c745de65L -_b = 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1L -_Gx = 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012L -_Gy = 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811L - -curve_192 = ellipticcurve.CurveFp( _p, -3, _b ) -generator_192 = ellipticcurve.Point( curve_192, _Gx, _Gy, _r ) - - -# NIST Curve P-224: -_p = 26959946667150639794667015087019630673557916260026308143510066298881L -_r = 26959946667150639794667015087019625940457807714424391721682722368061L -# s = 0xbd71344799d5c7fcdc45b59fa3b9ab8f6a948bc5L -# c = 0x5b056c7e11dd68f40469ee7f3c7a7d74f7d121116506d031218291fbL -_b = 0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4L -_Gx =0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21L -_Gy = 0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34L - -curve_224 = ellipticcurve.CurveFp( _p, -3, _b ) -generator_224 = ellipticcurve.Point( curve_224, _Gx, _Gy, _r ) - -# NIST Curve P-256: -_p = 115792089210356248762697446949407573530086143415290314195533631308867097853951L -_r = 115792089210356248762697446949407573529996955224135760342422259061068512044369L -# s = 0xc49d360886e704936a6678e1139d26b7819f7e90L -# c = 0x7efba1662985be9403cb055c75d4f7e0ce8d84a9c5114abcaf3177680104fa0dL -_b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604bL -_Gx = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296L -_Gy = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5L - -curve_256 = ellipticcurve.CurveFp( _p, -3, _b ) -generator_256 = ellipticcurve.Point( curve_256, _Gx, _Gy, _r ) - -# NIST Curve P-384: -_p = 39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319L -_r = 39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643L -# s = 0xa335926aa319a27a1d00896a6773a4827acdac73L -# c = 0x79d1e655f868f02fff48dcdee14151ddb80643c1406d0ca10dfe6fc52009540a495e8042ea5f744f6e184667cc722483L -_b = 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aefL -_Gx = 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7L -_Gy = 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5fL - -curve_384 = ellipticcurve.CurveFp( _p, -3, _b ) -generator_384 = ellipticcurve.Point( curve_384, _Gx, _Gy, _r ) - -# NIST Curve P-521: -_p = 6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151L -_r = 6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449L -# s = 0xd09e8800291cb85396cc6717393284aaa0da64baL -# c = 0x0b48bfa5f420a34949539d2bdfc264eeeeb077688e44fbf0ad8f6d0edb37bd6b533281000518e19f1b9ffbe0fe9ed8a3c2200b8f875e523868c70c1e5bf55bad637L -_b = 0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00L -_Gx = 0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66L -_Gy = 0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650L - -curve_521 = ellipticcurve.CurveFp( _p, -3, _b ) -generator_521 = ellipticcurve.Point( curve_521, _Gx, _Gy, _r ) - - - -def __main__(): - class TestFailure(Exception): pass - - def test_point_validity( generator, x, y, expected ): - """generator defines the curve; is (x,y) a point on - this curve? "expected" is True if the right answer is Yes.""" - if point_is_valid( generator, x, y ) == expected: - print "Point validity tested as expected." - else: - raise TestFailure("*** Point validity test gave wrong result.") - - def test_signature_validity( Msg, Qx, Qy, R, S, expected ): - """Msg = message, Qx and Qy represent the base point on - elliptic curve c192, R and S are the signature, and - "expected" is True iff the signature is expected to be valid.""" - pubk = Public_key( generator_192, - ellipticcurve.Point( curve_192, Qx, Qy ) ) - got = pubk.verifies( digest_integer( Msg ), Signature( R, S ) ) - if got == expected: - print "Signature tested as expected: got %s, expected %s." % \ - ( got, expected ) - else: - raise TestFailure("*** Signature test failed: got %s, expected %s." % \ - ( got, expected )) - - print "NIST Curve P-192:" - - p192 = generator_192 - - # From X9.62: - - d = 651056770906015076056810763456358567190100156695615665659L - Q = d * p192 - if Q.x() != 0x62B12D60690CDCF330BABAB6E69763B471F994DD702D16A5L: - raise TestFailure("*** p192 * d came out wrong.") - else: - print "p192 * d came out right." - - k = 6140507067065001063065065565667405560006161556565665656654L - R = k * p192 - if R.x() != 0x885052380FF147B734C330C43D39B2C4A89F29B0F749FEADL \ - or R.y() != 0x9CF9FA1CBEFEFB917747A3BB29C072B9289C2547884FD835L: - raise TestFailure("*** k * p192 came out wrong.") - else: - print "k * p192 came out right." - - u1 = 2563697409189434185194736134579731015366492496392189760599L - u2 = 6266643813348617967186477710235785849136406323338782220568L - temp = u1 * p192 + u2 * Q - if temp.x() != 0x885052380FF147B734C330C43D39B2C4A89F29B0F749FEADL \ - or temp.y() != 0x9CF9FA1CBEFEFB917747A3BB29C072B9289C2547884FD835L: - raise TestFailure("*** u1 * p192 + u2 * Q came out wrong.") - else: - print "u1 * p192 + u2 * Q came out right." - - e = 968236873715988614170569073515315707566766479517L - pubk = Public_key( generator_192, generator_192 * d ) - privk = Private_key( pubk, d ) - sig = privk.sign( e, k ) - r, s = sig.r, sig.s - if r != 3342403536405981729393488334694600415596881826869351677613L \ - or s != 5735822328888155254683894997897571951568553642892029982342L: - raise TestFailure("*** r or s came out wrong.") - else: - print "r and s came out right." - - valid = pubk.verifies( e, sig ) - if valid: print "Signature verified OK." - else: raise TestFailure("*** Signature failed verification.") - - valid = pubk.verifies( e-1, sig ) - if not valid: print "Forgery was correctly rejected." - else: raise TestFailure("*** Forgery was erroneously accepted.") - - print "Testing point validity, as per ECDSAVS.pdf B.2.2:" - - test_point_validity( \ - p192, \ - 0xcd6d0f029a023e9aaca429615b8f577abee685d8257cc83aL, \ - 0x00019c410987680e9fb6c0b6ecc01d9a2647c8bae27721bacdfcL, \ - False ) - - test_point_validity( - p192, \ - 0x00017f2fce203639e9eaf9fb50b81fc32776b30e3b02af16c73bL, \ - 0x95da95c5e72dd48e229d4748d4eee658a9a54111b23b2adbL, \ - False ) - - test_point_validity( - p192, \ - 0x4f77f8bc7fccbadd5760f4938746d5f253ee2168c1cf2792L, \ - 0x000147156ff824d131629739817edb197717c41aab5c2a70f0f6L, \ - False ) - - test_point_validity( - p192, \ - 0xc58d61f88d905293bcd4cd0080bcb1b7f811f2ffa41979f6L, \ - 0x8804dc7a7c4c7f8b5d437f5156f3312ca7d6de8a0e11867fL, \ - True ) - - test_point_validity( - p192, \ - 0xcdf56c1aa3d8afc53c521adf3ffb96734a6a630a4a5b5a70L, \ - 0x97c1c44a5fb229007b5ec5d25f7413d170068ffd023caa4eL, \ - True ) - - test_point_validity( - p192, \ - 0x89009c0dc361c81e99280c8e91df578df88cdf4b0cdedcedL, \ - 0x27be44a529b7513e727251f128b34262a0fd4d8ec82377b9L, \ - True ) - - test_point_validity( - p192, \ - 0x6a223d00bd22c52833409a163e057e5b5da1def2a197dd15L, \ - 0x7b482604199367f1f303f9ef627f922f97023e90eae08abfL, \ - True ) - - test_point_validity( - p192, \ - 0x6dccbde75c0948c98dab32ea0bc59fe125cf0fb1a3798edaL, \ - 0x0001171a3e0fa60cf3096f4e116b556198de430e1fbd330c8835L, \ - False ) - - test_point_validity( - p192, \ - 0xd266b39e1f491fc4acbbbc7d098430931cfa66d55015af12L, \ - 0x193782eb909e391a3148b7764e6b234aa94e48d30a16dbb2L, \ - False ) - - test_point_validity( - p192, \ - 0x9d6ddbcd439baa0c6b80a654091680e462a7d1d3f1ffeb43L, \ - 0x6ad8efc4d133ccf167c44eb4691c80abffb9f82b932b8caaL, \ - False ) - - test_point_validity( - p192, \ - 0x146479d944e6bda87e5b35818aa666a4c998a71f4e95edbcL, \ - 0xa86d6fe62bc8fbd88139693f842635f687f132255858e7f6L, \ - False ) - - test_point_validity( - p192, \ - 0xe594d4a598046f3598243f50fd2c7bd7d380edb055802253L, \ - 0x509014c0c4d6b536e3ca750ec09066af39b4c8616a53a923L, \ - False ) - - print "Trying signature-verification tests from ECDSAVS.pdf B.2.4:" - print "P-192:" - Msg = 0x84ce72aa8699df436059f052ac51b6398d2511e49631bcb7e71f89c499b9ee425dfbc13a5f6d408471b054f2655617cbbaf7937b7c80cd8865cf02c8487d30d2b0fbd8b2c4e102e16d828374bbc47b93852f212d5043c3ea720f086178ff798cc4f63f787b9c2e419efa033e7644ea7936f54462dc21a6c4580725f7f0e7d158L - Qx = 0xd9dbfb332aa8e5ff091e8ce535857c37c73f6250ffb2e7acL - Qy = 0x282102e364feded3ad15ddf968f88d8321aa268dd483ebc4L - R = 0x64dca58a20787c488d11d6dd96313f1b766f2d8efe122916L - S = 0x1ecba28141e84ab4ecad92f56720e2cc83eb3d22dec72479L - test_signature_validity( Msg, Qx, Qy, R, S, True ) - - Msg = 0x94bb5bacd5f8ea765810024db87f4224ad71362a3c28284b2b9f39fab86db12e8beb94aae899768229be8fdb6c4f12f28912bb604703a79ccff769c1607f5a91450f30ba0460d359d9126cbd6296be6d9c4bb96c0ee74cbb44197c207f6db326ab6f5a659113a9034e54be7b041ced9dcf6458d7fb9cbfb2744d999f7dfd63f4L - Qx = 0x3e53ef8d3112af3285c0e74842090712cd324832d4277ae7L - Qy = 0xcc75f8952d30aec2cbb719fc6aa9934590b5d0ff5a83adb7L - R = 0x8285261607283ba18f335026130bab31840dcfd9c3e555afL - S = 0x356d89e1b04541afc9704a45e9c535ce4a50929e33d7e06cL - test_signature_validity( Msg, Qx, Qy, R, S, True ) - - Msg = 0xf6227a8eeb34afed1621dcc89a91d72ea212cb2f476839d9b4243c66877911b37b4ad6f4448792a7bbba76c63bdd63414b6facab7dc71c3396a73bd7ee14cdd41a659c61c99b779cecf07bc51ab391aa3252386242b9853ea7da67fd768d303f1b9b513d401565b6f1eb722dfdb96b519fe4f9bd5de67ae131e64b40e78c42ddL - Qx = 0x16335dbe95f8e8254a4e04575d736befb258b8657f773cb7L - Qy = 0x421b13379c59bc9dce38a1099ca79bbd06d647c7f6242336L - R = 0x4141bd5d64ea36c5b0bd21ef28c02da216ed9d04522b1e91L - S = 0x159a6aa852bcc579e821b7bb0994c0861fb08280c38daa09L - test_signature_validity( Msg, Qx, Qy, R, S, False ) - - Msg = 0x16b5f93afd0d02246f662761ed8e0dd9504681ed02a253006eb36736b563097ba39f81c8e1bce7a16c1339e345efabbc6baa3efb0612948ae51103382a8ee8bc448e3ef71e9f6f7a9676694831d7f5dd0db5446f179bcb737d4a526367a447bfe2c857521c7f40b6d7d7e01a180d92431fb0bbd29c04a0c420a57b3ed26ccd8aL - Qx = 0xfd14cdf1607f5efb7b1793037b15bdf4baa6f7c16341ab0bL - Qy = 0x83fa0795cc6c4795b9016dac928fd6bac32f3229a96312c4L - R = 0x8dfdb832951e0167c5d762a473c0416c5c15bc1195667dc1L - S = 0x1720288a2dc13fa1ec78f763f8fe2ff7354a7e6fdde44520L - test_signature_validity( Msg, Qx, Qy, R, S, False ) - - Msg = 0x08a2024b61b79d260e3bb43ef15659aec89e5b560199bc82cf7c65c77d39192e03b9a895d766655105edd9188242b91fbde4167f7862d4ddd61e5d4ab55196683d4f13ceb90d87aea6e07eb50a874e33086c4a7cb0273a8e1c4408f4b846bceae1ebaac1b2b2ea851a9b09de322efe34cebe601653efd6ddc876ce8c2f2072fbL - Qx = 0x674f941dc1a1f8b763c9334d726172d527b90ca324db8828L - Qy = 0x65adfa32e8b236cb33a3e84cf59bfb9417ae7e8ede57a7ffL - R = 0x9508b9fdd7daf0d8126f9e2bc5a35e4c6d800b5b804d7796L - S = 0x36f2bf6b21b987c77b53bb801b3435a577e3d493744bfab0L - test_signature_validity( Msg, Qx, Qy, R, S, False ) - - Msg = 0x1843aba74b0789d4ac6b0b8923848023a644a7b70afa23b1191829bbe4397ce15b629bf21a8838298653ed0c19222b95fa4f7390d1b4c844d96e645537e0aae98afb5c0ac3bd0e4c37f8daaff25556c64e98c319c52687c904c4de7240a1cc55cd9756b7edaef184e6e23b385726e9ffcba8001b8f574987c1a3fedaaa83ca6dL - Qx = 0x10ecca1aad7220b56a62008b35170bfd5e35885c4014a19fL - Qy = 0x04eb61984c6c12ade3bc47f3c629ece7aa0a033b9948d686L - R = 0x82bfa4e82c0dfe9274169b86694e76ce993fd83b5c60f325L - S = 0xa97685676c59a65dbde002fe9d613431fb183e8006d05633L - test_signature_validity( Msg, Qx, Qy, R, S, False ) - - Msg = 0x5a478f4084ddd1a7fea038aa9732a822106385797d02311aeef4d0264f824f698df7a48cfb6b578cf3da416bc0799425bb491be5b5ecc37995b85b03420a98f2c4dc5c31a69a379e9e322fbe706bbcaf0f77175e05cbb4fa162e0da82010a278461e3e974d137bc746d1880d6eb02aa95216014b37480d84b87f717bb13f76e1L - Qx = 0x6636653cb5b894ca65c448277b29da3ad101c4c2300f7c04L - Qy = 0xfdf1cbb3fc3fd6a4f890b59e554544175fa77dbdbeb656c1L - R = 0xeac2ddecddfb79931a9c3d49c08de0645c783a24cb365e1cL - S = 0x3549fee3cfa7e5f93bc47d92d8ba100e881a2a93c22f8d50L - test_signature_validity( Msg, Qx, Qy, R, S, False ) - - Msg = 0xc598774259a058fa65212ac57eaa4f52240e629ef4c310722088292d1d4af6c39b49ce06ba77e4247b20637174d0bd67c9723feb57b5ead232b47ea452d5d7a089f17c00b8b6767e434a5e16c231ba0efa718a340bf41d67ea2d295812ff1b9277daacb8bc27b50ea5e6443bcf95ef4e9f5468fe78485236313d53d1c68f6ba2L - Qx = 0xa82bd718d01d354001148cd5f69b9ebf38ff6f21898f8aaaL - Qy = 0xe67ceede07fc2ebfafd62462a51e4b6c6b3d5b537b7caf3eL - R = 0x4d292486c620c3de20856e57d3bb72fcde4a73ad26376955L - S = 0xa85289591a6081d5728825520e62ff1c64f94235c04c7f95L - test_signature_validity( Msg, Qx, Qy, R, S, False ) - - Msg = 0xca98ed9db081a07b7557f24ced6c7b9891269a95d2026747add9e9eb80638a961cf9c71a1b9f2c29744180bd4c3d3db60f2243c5c0b7cc8a8d40a3f9a7fc910250f2187136ee6413ffc67f1a25e1c4c204fa9635312252ac0e0481d89b6d53808f0c496ba87631803f6c572c1f61fa049737fdacce4adff757afed4f05beb658L - Qx = 0x7d3b016b57758b160c4fca73d48df07ae3b6b30225126c2fL - Qy = 0x4af3790d9775742bde46f8da876711be1b65244b2b39e7ecL - R = 0x95f778f5f656511a5ab49a5d69ddd0929563c29cbc3a9e62L - S = 0x75c87fc358c251b4c83d2dd979faad496b539f9f2ee7a289L - test_signature_validity( Msg, Qx, Qy, R, S, False ) - - Msg = 0x31dd9a54c8338bea06b87eca813d555ad1850fac9742ef0bbe40dad400e10288acc9c11ea7dac79eb16378ebea9490e09536099f1b993e2653cd50240014c90a9c987f64545abc6a536b9bd2435eb5e911fdfde2f13be96ea36ad38df4ae9ea387b29cced599af777338af2794820c9cce43b51d2112380a35802ab7e396c97aL - Qx = 0x9362f28c4ef96453d8a2f849f21e881cd7566887da8beb4aL - Qy = 0xe64d26d8d74c48a024ae85d982ee74cd16046f4ee5333905L - R = 0xf3923476a296c88287e8de914b0b324ad5a963319a4fe73bL - S = 0xf0baeed7624ed00d15244d8ba2aede085517dbdec8ac65f5L - test_signature_validity( Msg, Qx, Qy, R, S, True ) - - Msg = 0xb2b94e4432267c92f9fdb9dc6040c95ffa477652761290d3c7de312283f6450d89cc4aabe748554dfb6056b2d8e99c7aeaad9cdddebdee9dbc099839562d9064e68e7bb5f3a6bba0749ca9a538181fc785553a4000785d73cc207922f63e8ce1112768cb1de7b673aed83a1e4a74592f1268d8e2a4e9e63d414b5d442bd0456dL - Qx = 0xcc6fc032a846aaac25533eb033522824f94e670fa997ecefL - Qy = 0xe25463ef77a029eccda8b294fd63dd694e38d223d30862f1L - R = 0x066b1d07f3a40e679b620eda7f550842a35c18b80c5ebe06L - S = 0xa0b0fb201e8f2df65e2c4508ef303bdc90d934016f16b2dcL - test_signature_validity( Msg, Qx, Qy, R, S, False ) - - Msg = 0x4366fcadf10d30d086911de30143da6f579527036937007b337f7282460eae5678b15cccda853193ea5fc4bc0a6b9d7a31128f27e1214988592827520b214eed5052f7775b750b0c6b15f145453ba3fee24a085d65287e10509eb5d5f602c440341376b95c24e5c4727d4b859bfe1483d20538acdd92c7997fa9c614f0f839d7L - Qx = 0x955c908fe900a996f7e2089bee2f6376830f76a19135e753L - Qy = 0xba0c42a91d3847de4a592a46dc3fdaf45a7cc709b90de520L - R = 0x1f58ad77fc04c782815a1405b0925e72095d906cbf52a668L - S = 0xf2e93758b3af75edf784f05a6761c9b9a6043c66b845b599L - test_signature_validity( Msg, Qx, Qy, R, S, False ) - - Msg = 0x543f8af57d750e33aa8565e0cae92bfa7a1ff78833093421c2942cadf9986670a5ff3244c02a8225e790fbf30ea84c74720abf99cfd10d02d34377c3d3b41269bea763384f372bb786b5846f58932defa68023136cd571863b304886e95e52e7877f445b9364b3f06f3c28da12707673fecb4b8071de06b6e0a3c87da160cef3L - Qx = 0x31f7fa05576d78a949b24812d4383107a9a45bb5fccdd835L - Qy = 0x8dc0eb65994a90f02b5e19bd18b32d61150746c09107e76bL - R = 0xbe26d59e4e883dde7c286614a767b31e49ad88789d3a78ffL - S = 0x8762ca831c1ce42df77893c9b03119428e7a9b819b619068L - test_signature_validity( Msg, Qx, Qy, R, S, False ) - - Msg = 0xd2e8454143ce281e609a9d748014dcebb9d0bc53adb02443a6aac2ffe6cb009f387c346ecb051791404f79e902ee333ad65e5c8cb38dc0d1d39a8dc90add5023572720e5b94b190d43dd0d7873397504c0c7aef2727e628eb6a74411f2e400c65670716cb4a815dc91cbbfeb7cfe8c929e93184c938af2c078584da045e8f8d1L - Qx = 0x66aa8edbbdb5cf8e28ceb51b5bda891cae2df84819fe25c0L - Qy = 0x0c6bc2f69030a7ce58d4a00e3b3349844784a13b8936f8daL - R = 0xa4661e69b1734f4a71b788410a464b71e7ffe42334484f23L - S = 0x738421cf5e049159d69c57a915143e226cac8355e149afe9L - test_signature_validity( Msg, Qx, Qy, R, S, False ) - - Msg = 0x6660717144040f3e2f95a4e25b08a7079c702a8b29babad5a19a87654bc5c5afa261512a11b998a4fb36b5d8fe8bd942792ff0324b108120de86d63f65855e5461184fc96a0a8ffd2ce6d5dfb0230cbbdd98f8543e361b3205f5da3d500fdc8bac6db377d75ebef3cb8f4d1ff738071ad0938917889250b41dd1d98896ca06fbL - Qx = 0xbcfacf45139b6f5f690a4c35a5fffa498794136a2353fc77L - Qy = 0x6f4a6c906316a6afc6d98fe1f0399d056f128fe0270b0f22L - R = 0x9db679a3dafe48f7ccad122933acfe9da0970b71c94c21c1L - S = 0x984c2db99827576c0a41a5da41e07d8cc768bc82f18c9da9L - test_signature_validity( Msg, Qx, Qy, R, S, False ) - - - - print "Testing the example code:" - - # Building a public/private key pair from the NIST Curve P-192: - - g = generator_192 - n = g.order() - - # (random.SystemRandom is supposed to provide - # crypto-quality random numbers, but as Debian recently - # illustrated, a systems programmer can accidentally - # demolish this security, so in serious applications - # further precautions are appropriate.) - - randrange = random.SystemRandom().randrange - - secret = randrange( 1, n ) - pubkey = Public_key( g, g * secret ) - privkey = Private_key( pubkey, secret ) - - # Signing a hash value: - - hash = randrange( 1, n ) - signature = privkey.sign( hash, randrange( 1, n ) ) - - # Verifying a signature for a hash value: - - if pubkey.verifies( hash, signature ): - print "Demo verification succeeded." - else: - raise TestFailure("*** Demo verification failed.") - - if pubkey.verifies( hash-1, signature ): - raise TestFailure( "**** Demo verification failed to reject tampered hash.") - else: - print "Demo verification correctly rejected tampered hash." - -if __name__ == "__main__": - __main__() diff --git a/ecdsa/ellipticcurve.py b/ecdsa/ellipticcurve.py @@ -1,290 +0,0 @@ -#! /usr/bin/env python -# -# Implementation of elliptic curves, for cryptographic applications. -# -# This module doesn't provide any way to choose a random elliptic -# curve, nor to verify that an elliptic curve was chosen randomly, -# because one can simply use NIST's standard curves. -# -# Notes from X9.62-1998 (draft): -# Nomenclature: -# - Q is a public key. -# The "Elliptic Curve Domain Parameters" include: -# - q is the "field size", which in our case equals p. -# - p is a big prime. -# - G is a point of prime order (5.1.1.1). -# - n is the order of G (5.1.1.1). -# Public-key validation (5.2.2): -# - Verify that Q is not the point at infinity. -# - Verify that X_Q and Y_Q are in [0,p-1]. -# - Verify that Q is on the curve. -# - Verify that nQ is the point at infinity. -# Signature generation (5.3): -# - Pick random k from [1,n-1]. -# Signature checking (5.4.2): -# - Verify that r and s are in [1,n-1]. -# -# Version of 2008.11.25. -# -# Revision history: -# 2005.12.31 - Initial version. -# 2008.11.25 - Change CurveFp.is_on to contains_point. -# -# Written in 2005 by Peter Pearson and placed in the public domain. - -import numbertheory - -class CurveFp( object ): - """Elliptic Curve over the field of integers modulo a prime.""" - def __init__( self, p, a, b ): - """The curve of points satisfying y^2 = x^3 + a*x + b (mod p).""" - self.__p = p - self.__a = a - self.__b = b - - def p( self ): - return self.__p - - def a( self ): - return self.__a - - def b( self ): - return self.__b - - def contains_point( self, x, y ): - """Is the point (x,y) on this curve?""" - return ( y * y - ( x * x * x + self.__a * x + self.__b ) ) % self.__p == 0 - - - -class Point( object ): - """A point on an elliptic curve. Altering x and y is forbidding, - but they can be read by the x() and y() methods.""" - def __init__( self, curve, x, y, order = None ): - """curve, x, y, order; order (optional) is the order of this point.""" - self.__curve = curve - self.__x = x - self.__y = y - self.__order = order - # self.curve is allowed to be None only for INFINITY: - if self.__curve: assert self.__curve.contains_point( x, y ) - if order: assert self * order == INFINITY - - def __cmp__( self, other ): - """Return 0 if the points are identical, 1 otherwise.""" - if self.__curve == other.__curve \ - and self.__x == other.__x \ - and self.__y == other.__y: - return 0 - else: - return 1 - - def __add__( self, other ): - """Add one point to another point.""" - - # X9.62 B.3: - - if other == INFINITY: return self - if self == INFINITY: return other - assert self.__curve == other.__curve - if self.__x == other.__x: - if ( self.__y + other.__y ) % self.__curve.p() == 0: - return INFINITY - else: - return self.double() - - p = self.__curve.p() - - l = ( ( other.__y - self.__y ) * \ - numbertheory.inverse_mod( other.__x - self.__x, p ) ) % p - - x3 = ( l * l - self.__x - other.__x ) % p - y3 = ( l * ( self.__x - x3 ) - self.__y ) % p - - return Point( self.__curve, x3, y3 ) - - def __mul__( self, other ): - """Multiply a point by an integer.""" - - def leftmost_bit( x ): - assert x > 0 - result = 1L - while result <= x: result = 2 * result - return result // 2 - - e = other - if self.__order: e = e % self.__order - if e == 0: return INFINITY - if self == INFINITY: return INFINITY - assert e > 0 - - # From X9.62 D.3.2: - - e3 = 3 * e - negative_self = Point( self.__curve, self.__x, -self.__y, self.__order ) - i = leftmost_bit( e3 ) // 2 - result = self - # print "Multiplying %s by %d (e3 = %d):" % ( self, other, e3 ) - while i > 1: - result = result.double() - if ( e3 & i ) != 0 and ( e & i ) == 0: result = result + self - if ( e3 & i ) == 0 and ( e & i ) != 0: result = result + negative_self - # print ". . . i = %d, result = %s" % ( i, result ) - i = i // 2 - - return result - - def __rmul__( self, other ): - """Multiply a point by an integer.""" - - return self * other - - def __str__( self ): - if self == INFINITY: return "infinity" - return "(%d,%d)" % ( self.__x, self.__y ) - - def double( self ): - """Return a new point that is twice the old.""" - - if self == INFINITY: - return INFINITY - - # X9.62 B.3: - - p = self.__curve.p() - a = self.__curve.a() - - l = ( ( 3 * self.__x * self.__x + a ) * \ - numbertheory.inverse_mod( 2 * self.__y, p ) ) % p - - x3 = ( l * l - 2 * self.__x ) % p - y3 = ( l * ( self.__x - x3 ) - self.__y ) % p - - return Point( self.__curve, x3, y3 ) - - def x( self ): - return self.__x - - def y( self ): - return self.__y - - def curve( self ): - return self.__curve - - def order( self ): - return self.__order - - -# This one point is the Point At Infinity for all purposes: -INFINITY = Point( None, None, None ) - -def __main__(): - - class FailedTest(Exception): pass - def test_add( c, x1, y1, x2, y2, x3, y3 ): - """We expect that on curve c, (x1,y1) + (x2, y2 ) = (x3, y3).""" - p1 = Point( c, x1, y1 ) - p2 = Point( c, x2, y2 ) - p3 = p1 + p2 - print "%s + %s = %s" % ( p1, p2, p3 ), - if p3.x() != x3 or p3.y() != y3: - raise FailedTest("Failure: should give (%d,%d)." % ( x3, y3 )) - else: - print " Good." - - def test_double( c, x1, y1, x3, y3 ): - """We expect that on curve c, 2*(x1,y1) = (x3, y3).""" - p1 = Point( c, x1, y1 ) - p3 = p1.double() - print "%s doubled = %s" % ( p1, p3 ), - if p3.x() != x3 or p3.y() != y3: - raise FailedTest("Failure: should give (%d,%d)." % ( x3, y3 )) - else: - print " Good." - - def test_double_infinity( c ): - """We expect that on curve c, 2*INFINITY = INFINITY.""" - p1 = INFINITY - p3 = p1.double() - print "%s doubled = %s" % ( p1, p3 ), - if p3.x() != INFINITY.x() or p3.y() != INFINITY.y(): - raise FailedTest("Failure: should give (%d,%d)." % ( INFINITY.x(), INFINITY.y() )) - else: - print " Good." - - def test_multiply( c, x1, y1, m, x3, y3 ): - """We expect that on curve c, m*(x1,y1) = (x3,y3).""" - p1 = Point( c, x1, y1 ) - p3 = p1 * m - print "%s * %d = %s" % ( p1, m, p3 ), - if p3.x() != x3 or p3.y() != y3: - raise FailedTest("Failure: should give (%d,%d)." % ( x3, y3 )) - else: - print " Good." - - - # A few tests from X9.62 B.3: - - c = CurveFp( 23, 1, 1 ) - test_add( c, 3, 10, 9, 7, 17, 20 ) - test_double( c, 3, 10, 7, 12 ) - test_add( c, 3, 10, 3, 10, 7, 12 ) # (Should just invoke double.) - test_multiply( c, 3, 10, 2, 7, 12 ) - - test_double_infinity(c) - - # From X9.62 I.1 (p. 96): - - g = Point( c, 13, 7, 7 ) - - check = INFINITY - for i in range( 7 + 1 ): - p = ( i % 7 ) * g - print "%s * %d = %s, expected %s . . ." % ( g, i, p, check ), - if p == check: - print " Good." - else: - raise FailedTest("Bad.") - check = check + g - - # NIST Curve P-192: - p = 6277101735386680763835789423207666416083908700390324961279L - r = 6277101735386680763835789423176059013767194773182842284081L - #s = 0x3045ae6fc8422f64ed579528d38120eae12196d5L - c = 0x3099d2bbbfcb2538542dcd5fb078b6ef5f3d6fe2c745de65L - b = 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1L - Gx = 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012L - Gy = 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811L - - c192 = CurveFp( p, -3, b ) - p192 = Point( c192, Gx, Gy, r ) - - # Checking against some sample computations presented - # in X9.62: - - d = 651056770906015076056810763456358567190100156695615665659L - Q = d * p192 - if Q.x() != 0x62B12D60690CDCF330BABAB6E69763B471F994DD702D16A5L: - raise FailedTest("p192 * d came out wrong.") - else: - print "p192 * d came out right." - - k = 6140507067065001063065065565667405560006161556565665656654L - R = k * p192 - if R.x() != 0x885052380FF147B734C330C43D39B2C4A89F29B0F749FEADL \ - or R.y() != 0x9CF9FA1CBEFEFB917747A3BB29C072B9289C2547884FD835L: - raise FailedTest("k * p192 came out wrong.") - else: - print "k * p192 came out right." - - u1 = 2563697409189434185194736134579731015366492496392189760599L - u2 = 6266643813348617967186477710235785849136406323338782220568L - temp = u1 * p192 + u2 * Q - if temp.x() != 0x885052380FF147B734C330C43D39B2C4A89F29B0F749FEADL \ - or temp.y() != 0x9CF9FA1CBEFEFB917747A3BB29C072B9289C2547884FD835L: - raise FailedTest("u1 * p192 + u2 * Q came out wrong.") - else: - print "u1 * p192 + u2 * Q came out right." - -if __name__ == "__main__": - __main__() diff --git a/ecdsa/keys.py b/ecdsa/keys.py @@ -1,252 +0,0 @@ -import binascii - -import ecdsa -import der -from curves import NIST192p, find_curve -from util import string_to_number, number_to_string, randrange -from util import sigencode_string, sigdecode_string -from util import oid_ecPublicKey, encoded_oid_ecPublicKey -from hashlib import sha1 - -class BadSignatureError(Exception): - pass -class BadDigestError(Exception): - pass - -class VerifyingKey: - def __init__(self, _error__please_use_generate=None): - if not _error__please_use_generate: - raise TypeError("Please use SigningKey.generate() to construct me") - - @classmethod - def from_public_point(klass, point, curve=NIST192p, hashfunc=sha1): - self = klass(_error__please_use_generate=True) - self.curve = curve - self.default_hashfunc = hashfunc - self.pubkey = ecdsa.Public_key(curve.generator, point) - self.pubkey.order = curve.order - return self - - @classmethod - def from_string(klass, string, curve=NIST192p, hashfunc=sha1): - order = curve.order - assert len(string) == curve.verifying_key_length, \ - (len(string), curve.verifying_key_length) - xs = string[:curve.baselen] - ys = string[curve.baselen:] - assert len(xs) == curve.baselen, (len(xs), curve.baselen) - assert len(ys) == curve.baselen, (len(ys), curve.baselen) - x = string_to_number(xs) - y = string_to_number(ys) - assert ecdsa.point_is_valid(curve.generator, x, y) - import ellipticcurve - point = ellipticcurve.Point(curve.curve, x, y, order) - return klass.from_public_point(point, curve, hashfunc) - - @classmethod - def from_pem(klass, string): - return klass.from_der(der.unpem(string)) - - @classmethod - def from_der(klass, string): - # [[oid_ecPublicKey,oid_curve], point_str_bitstring] - s1,empty = der.remove_sequence(string) - if empty != "": - raise der.UnexpectedDER("trailing junk after DER pubkey: %s" % - binascii.hexlify(empty)) - s2,point_str_bitstring = der.remove_sequence(s1) - # s2 = oid_ecPublicKey,oid_curve - oid_pk, rest = der.remove_object(s2) - oid_curve, empty = der.remove_object(rest) - if empty != "": - raise der.UnexpectedDER("trailing junk after DER pubkey objects: %s" % - binascii.hexlify(empty)) - assert oid_pk == oid_ecPublicKey, (oid_pk, oid_ecPublicKey) - curve = find_curve(oid_curve) - point_str, empty = der.remove_bitstring(point_str_bitstring) - if empty != "": - raise der.UnexpectedDER("trailing junk after pubkey pointstring: %s" % - binascii.hexlify(empty)) - assert point_str.startswith("\x00\x04") - return klass.from_string(point_str[2:], curve) - - def to_string(self): - # VerifyingKey.from_string(vk.to_string()) == vk as long as the - # curves are the same: the curve itself is not included in the - # serialized form - order = self.pubkey.order - x_str = number_to_string(self.pubkey.point.x(), order) - y_str = number_to_string(self.pubkey.point.y(), order) - return x_str + y_str - - def to_pem(self): - return der.topem(self.to_der(), "PUBLIC KEY") - - def to_der(self): - order = self.pubkey.order - x_str = number_to_string(self.pubkey.point.x(), order) - y_str = number_to_string(self.pubkey.point.y(), order) - point_str = "\x00\x04" + x_str + y_str - return der.encode_sequence(der.encode_sequence(encoded_oid_ecPublicKey, - self.curve.encoded_oid), - der.encode_bitstring(point_str)) - - def verify(self, signature, data, hashfunc=None, sigdecode=sigdecode_string): - hashfunc = hashfunc or self.default_hashfunc - digest = hashfunc(data).digest() - return self.verify_digest(signature, digest, sigdecode) - - def verify_digest(self, signature, digest, sigdecode=sigdecode_string): - if len(digest) > self.curve.baselen: - raise BadDigestError("this curve (%s) is too short " - "for your digest (%d)" % (self.curve.name, - 8*len(digest))) - number = string_to_number(digest) - r, s = sigdecode(signature, self.pubkey.order) - sig = ecdsa.Signature(r, s) - if self.pubkey.verifies(number, sig): - return True - raise BadSignatureError - -class SigningKey: - def __init__(self, _error__please_use_generate=None): - if not _error__please_use_generate: - raise TypeError("Please use SigningKey.generate() to construct me") - - @classmethod - def generate(klass, curve=NIST192p, entropy=None, hashfunc=sha1): - secexp = randrange(curve.order, entropy) - return klass.from_secret_exponent(secexp, curve, hashfunc) - - # to create a signing key from a short (arbitrary-length) seed, convert - # that seed into an integer with something like - # secexp=util.randrange_from_seed__X(seed, curve.order), and then pass - # that integer into SigningKey.from_secret_exponent(secexp, curve) - - @classmethod - def from_secret_exponent(klass, secexp, curve=NIST192p, hashfunc=sha1): - self = klass(_error__please_use_generate=True) - self.curve = curve - self.default_hashfunc = hashfunc - self.baselen = curve.baselen - n = curve.order - assert 1 <= secexp < n - pubkey_point = curve.generator*secexp - pubkey = ecdsa.Public_key(curve.generator, pubkey_point) - pubkey.order = n - self.verifying_key = VerifyingKey.from_public_point(pubkey_point, curve, - hashfunc) - self.privkey = ecdsa.Private_key(pubkey, secexp) - self.privkey.order = n - return self - - @classmethod - def from_string(klass, string, curve=NIST192p, hashfunc=sha1): - assert len(string) == curve.baselen, (len(string), curve.baselen) - secexp = string_to_number(string) - return klass.from_secret_exponent(secexp, curve, hashfunc) - - @classmethod - def from_pem(klass, string, hashfunc=sha1): - # the privkey pem file has two sections: "EC PARAMETERS" and "EC - # PRIVATE KEY". The first is redundant. - privkey_pem = string[string.index("-----BEGIN EC PRIVATE KEY-----"):] - return klass.from_der(der.unpem(privkey_pem), hashfunc) - @classmethod - def from_der(klass, string, hashfunc=sha1): - # SEQ([int(1), octetstring(privkey),cont[0], oid(secp224r1), - # cont[1],bitstring]) - s, empty = der.remove_sequence(string) - if empty != "": - raise der.UnexpectedDER("trailing junk after DER privkey: %s" % - binascii.hexlify(empty)) - one, s = der.remove_integer(s) - if one != 1: - raise der.UnexpectedDER("expected '1' at start of DER privkey," - " got %d" % one) - privkey_str, s = der.remove_octet_string(s) - tag, curve_oid_str, s = der.remove_constructed(s) - if tag != 0: - raise der.UnexpectedDER("expected tag 0 in DER privkey," - " got %d" % tag) - curve_oid, empty = der.remove_object(curve_oid_str) - if empty != "": - raise der.UnexpectedDER("trailing junk after DER privkey " - "curve_oid: %s" % binascii.hexlify(empty)) - curve = find_curve(curve_oid) - - # we don't actually care about the following fields - # - #tag, pubkey_bitstring, s = der.remove_constructed(s) - #if tag != 1: - # raise der.UnexpectedDER("expected tag 1 in DER privkey, got %d" - # % tag) - #pubkey_str = der.remove_bitstring(pubkey_bitstring) - #if empty != "": - # raise der.UnexpectedDER("trailing junk after DER privkey " - # "pubkeystr: %s" % binascii.hexlify(empty)) - - # our from_string method likes fixed-length privkey strings - if len(privkey_str) < curve.baselen: - privkey_str = "\x00"*(curve.baselen-len(privkey_str)) + privkey_str - return klass.from_string(privkey_str, curve, hashfunc) - - def to_string(self): - secexp = self.privkey.secret_multiplier - s = number_to_string(secexp, self.privkey.order) - return s - - def to_pem(self): - # TODO: "BEGIN ECPARAMETERS" - return der.topem(self.to_der(), "EC PRIVATE KEY") - - def to_der(self): - # SEQ([int(1), octetstring(privkey),cont[0], oid(secp224r1), - # cont[1],bitstring]) - encoded_vk = "\x00\x04" + self.get_verifying_key().to_string() - return der.encode_sequence(der.encode_integer(1), - der.encode_octet_string(self.to_string()), - der.encode_constructed(0, self.curve.encoded_oid), - der.encode_constructed(1, der.encode_bitstring(encoded_vk)), - ) - - def get_verifying_key(self): - return self.verifying_key - - def sign(self, data, entropy=None, hashfunc=None, sigencode=sigencode_string): - """ - hashfunc= should behave like hashlib.sha1 . The output length of the - hash (in bytes) must not be longer than the length of the curve order - (rounded up to the nearest byte), so using SHA256 with nist256p is - ok, but SHA256 with nist192p is not. (In the 2**-96ish unlikely event - of a hash output larger than the curve order, the hash will - effectively be wrapped mod n). - - Use hashfunc=hashlib.sha1 to match openssl's -ecdsa-with-SHA1 mode, - or hashfunc=hashlib.sha256 for openssl-1.0.0's -ecdsa-with-SHA256. - """ - - hashfunc = hashfunc or self.default_hashfunc - h = hashfunc(data).digest() - return self.sign_digest(h, entropy, sigencode) - - def sign_digest(self, digest, entropy=None, sigencode=sigencode_string): - if len(digest) > self.curve.baselen: - raise BadDigestError("this curve (%s) is too short " - "for your digest (%d)" % (self.curve.name, - 8*len(digest))) - number = string_to_number(digest) - r, s = self.sign_number(number, entropy) - return sigencode(r, s, self.privkey.order) - - def sign_number(self, number, entropy=None): - # returns a pair of numbers - order = self.privkey.order - # privkey.sign() may raise RuntimeError in the amazingly unlikely - # (2**-192) event that r=0 or s=0, because that would leak the key. - # We could re-try with a different 'k', but we couldn't test that - # code, so I choose to allow the signature to fail instead. - k = randrange(order, entropy) - assert 1 <= k < order - sig = self.privkey.sign(number, k) - return sig.r, sig.s diff --git a/ecdsa/numbertheory.py b/ecdsa/numbertheory.py @@ -1,614 +0,0 @@ -#! /usr/bin/env python -# -# Provide some simple capabilities from number theory. -# -# Version of 2008.11.14. -# -# Written in 2005 and 2006 by Peter Pearson and placed in the public domain. -# Revision history: -# 2008.11.14: Use pow( base, exponent, modulus ) for modular_exp. -# Make gcd and lcm accept arbitrarly many arguments. - - - -import math -import types - - -class Error( Exception ): - """Base class for exceptions in this module.""" - pass - -class SquareRootError( Error ): - pass - -class NegativeExponentError( Error ): - pass - - -def modular_exp( base, exponent, modulus ): - "Raise base to exponent, reducing by modulus" - if exponent < 0: - raise NegativeExponentError( "Negative exponents (%d) not allowed" \ - % exponent ) - return pow( base, exponent, modulus ) -# result = 1L -# x = exponent -# b = base + 0L -# while x > 0: -# if x % 2 > 0: result = (result * b) % modulus -# x = x // 2 -# b = ( b * b ) % modulus -# return result - - -def polynomial_reduce_mod( poly, polymod, p ): - """Reduce poly by polymod, integer arithmetic modulo p. - - Polynomials are represented as lists of coefficients - of increasing powers of x.""" - - # This module has been tested only by extensive use - # in calculating modular square roots. - - # Just to make this easy, require a monic polynomial: - assert polymod[-1] == 1 - - assert len( polymod ) > 1 - - while len( poly ) >= len( polymod ): - if poly[-1] != 0: - for i in range( 2, len( polymod ) + 1 ): - poly[-i] = ( poly[-i] - poly[-1] * polymod[-i] ) % p - poly = poly[0:-1] - - return poly - - - -def polynomial_multiply_mod( m1, m2, polymod, p ): - """Polynomial multiplication modulo a polynomial over ints mod p. - - Polynomials are represented as lists of coefficients - of increasing powers of x.""" - - # This is just a seat-of-the-pants implementation. - - # This module has been tested only by extensive use - # in calculating modular square roots. - - # Initialize the product to zero: - - prod = ( len( m1 ) + len( m2 ) - 1 ) * [0] - - # Add together all the cross-terms: - - for i in range( len( m1 ) ): - for j in range( len( m2 ) ): - prod[i+j] = ( prod[i+j] + m1[i] * m2[j] ) % p - - return polynomial_reduce_mod( prod, polymod, p ) - - - - -def polynomial_exp_mod( base, exponent, polymod, p ): - """Polynomial exponentiation modulo a polynomial over ints mod p. - - Polynomials are represented as lists of coefficients - of increasing powers of x.""" - - # Based on the Handbook of Applied Cryptography, algorithm 2.227. - - # This module has been tested only by extensive use - # in calculating modular square roots. - - assert exponent < p - - if exponent == 0: return [ 1 ] - - G = base - k = exponent - if k%2 == 1: s = G - else: s = [ 1 ] - - while k > 1: - k = k // 2 - G = polynomial_multiply_mod( G, G, polymod, p ) - if k%2 == 1: s = polynomial_multiply_mod( G, s, polymod, p ) - - return s - - - -def jacobi( a, n ): - """Jacobi symbol""" - - # Based on the Handbook of Applied Cryptography (HAC), algorithm 2.149. - - # This function has been tested by comparison with a small - # table printed in HAC, and by extensive use in calculating - # modular square roots. - - assert n >= 3 - assert n%2 == 1 - a = a % n - if a == 0: return 0 - if a == 1: return 1 - a1, e = a, 0 - while a1%2 == 0: - a1, e = a1//2, e+1 - if e%2 == 0 or n%8 == 1 or n%8 == 7: s = 1 - else: s = -1 - if a1 == 1: return s - if n%4 == 3 and a1%4 == 3: s = -s - return s * jacobi( n % a1, a1 ) - - - - -def square_root_mod_prime( a, p ): - """Modular square root of a, mod p, p prime.""" - - # Based on the Handbook of Applied Cryptography, algorithms 3.34 to 3.39. - - # This module has been tested for all values in [0,p-1] for - # every prime p from 3 to 1229. - - assert 0 <= a < p - assert 1 < p - - if a == 0: return 0 - if p == 2: return a - - jac = jacobi( a, p ) - if jac == -1: raise SquareRootError( "%d has no square root modulo %d" \ - % ( a, p ) ) - - if p % 4 == 3: return modular_exp( a, (p+1)//4, p ) - - if p % 8 == 5: - d = modular_exp( a, (p-1)//4, p ) - if d == 1: return modular_exp( a, (p+3)//8, p ) - if d == p-1: return ( 2 * a * modular_exp( 4*a, (p-5)//8, p ) ) % p - raise RuntimeError, "Shouldn't get here." - - for b in range( 2, p ): - if jacobi( b*b-4*a, p ) == -1: - f = ( a, -b, 1 ) - ff = polynomial_exp_mod( ( 0, 1 ), (p+1)//2, f, p ) - assert ff[1] == 0 - return ff[0] - raise RuntimeError, "No b found." - - - -def inverse_mod( a, m ): - """Inverse of a mod m.""" - - if a < 0 or m <= a: a = a % m - - # From Ferguson and Schneier, roughly: - - c, d = a, m - uc, vc, ud, vd = 1, 0, 0, 1 - while c != 0: - q, c, d = divmod( d, c ) + ( c, ) - uc, vc, ud, vd = ud - q*uc, vd - q*vc, uc, vc - - # At this point, d is the GCD, and ud*a+vd*m = d. - # If d == 1, this means that ud is a inverse. - - assert d == 1 - if ud > 0: return ud - else: return ud + m - - -def gcd2(a, b): - """Greatest common divisor using Euclid's algorithm.""" - while a: - a, b = b%a, a - return b - - -def gcd( *a ): - """Greatest common divisor. - - Usage: gcd( [ 2, 4, 6 ] ) - or: gcd( 2, 4, 6 ) - """ - - if len( a ) > 1: return reduce( gcd2, a ) - if hasattr( a[0], "__iter__" ): return reduce( gcd2, a[0] ) - return a[0] - - -def lcm2(a,b): - """Least common multiple of two integers.""" - - return (a*b)//gcd(a,b) - - -def lcm( *a ): - """Least common multiple. - - Usage: lcm( [ 3, 4, 5 ] ) - or: lcm( 3, 4, 5 ) - """ - - if len( a ) > 1: return reduce( lcm2, a ) - if hasattr( a[0], "__iter__" ): return reduce( lcm2, a[0] ) - return a[0] - - - -def factorization( n ): - """Decompose n into a list of (prime,exponent) pairs.""" - - assert isinstance( n, types.IntType ) or isinstance( n, types.LongType ) - - if n < 2: return [] - - result = [] - d = 2 - - # Test the small primes: - - for d in smallprimes: - if d > n: break - q, r = divmod( n, d ) - if r == 0: - count = 1 - while d <= n: - n = q - q, r = divmod( n, d ) - if r != 0: break - count = count + 1 - result.append( ( d, count ) ) - - # If n is still greater than the last of our small primes, - # it may require further work: - - if n > smallprimes[-1]: - if is_prime( n ): # If what's left is prime, it's easy: - result.append( ( n, 1 ) ) - else: # Ugh. Search stupidly for a divisor: - d = smallprimes[-1] - while 1: - d = d + 2 # Try the next divisor. - q, r = divmod( n, d ) - if q < d: break # n < d*d means we're done, n = 1 or prime. - if r == 0: # d divides n. How many times? - count = 1 - n = q - while d <= n: # As long as d might still divide n, - q, r = divmod( n, d ) # see if it does. - if r != 0: break - n = q # It does. Reduce n, increase count. - count = count + 1 - result.append( ( d, count ) ) - if n > 1: result.append( ( n, 1 ) ) - - return result - - - -def phi( n ): - """Return the Euler totient function of n.""" - - assert isinstance( n, types.IntType ) or isinstance( n, types.LongType ) - - if n < 3: return 1 - - result = 1 - ff = factorization( n ) - for f in ff: - e = f[1] - if e > 1: - result = result * f[0] ** (e-1) * ( f[0] - 1 ) - else: - result = result * ( f[0] - 1 ) - return result - - -def carmichael( n ): - """Return Carmichael function of n. - - Carmichael(n) is the smallest integer x such that - m**x = 1 mod n for all m relatively prime to n. - """ - - return carmichael_of_factorized( factorization( n ) ) - - -def carmichael_of_factorized( f_list ): - """Return the Carmichael function of a number that is - represented as a list of (prime,exponent) pairs. - """ - - if len( f_list ) < 1: return 1 - - result = carmichael_of_ppower( f_list[0] ) - for i in range( 1, len( f_list ) ): - result = lcm( result, carmichael_of_ppower( f_list[i] ) ) - - return result - -def carmichael_of_ppower( pp ): - """Carmichael function of the given power of the given prime. - """ - - p, a = pp - if p == 2 and a > 2: return 2**(a-2) - else: return (p-1) * p**(a-1) - - - -def order_mod( x, m ): - """Return the order of x in the multiplicative group mod m. - """ - - # Warning: this implementation is not very clever, and will - # take a long time if m is very large. - - if m <= 1: return 0 - - assert gcd( x, m ) == 1 - - z = x - result = 1 - while z != 1: - z = ( z * x ) % m - result = result + 1 - return result - - -def largest_factor_relatively_prime( a, b ): - """Return the largest factor of a relatively prime to b. - """ - - while 1: - d = gcd( a, b ) - if d <= 1: break - b = d - while 1: - q, r = divmod( a, d ) - if r > 0: - break - a = q - return a - - -def kinda_order_mod( x, m ): - """Return the order of x in the multiplicative group mod m', - where m' is the largest factor of m relatively prime to x. - """ - - return order_mod( x, largest_factor_relatively_prime( m, x ) ) - - -def is_prime( n ): - """Return True if x is prime, False otherwise. - - We use the Miller-Rabin test, as given in Menezes et al. p. 138. - This test is not exact: there are composite values n for which - it returns True. - - In testing the odd numbers from 10000001 to 19999999, - about 66 composites got past the first test, - 5 got past the second test, and none got past the third. - Since factors of 2, 3, 5, 7, and 11 were detected during - preliminary screening, the number of numbers tested by - Miller-Rabin was (19999999 - 10000001)*(2/3)*(4/5)*(6/7) - = 4.57 million. - """ - - # (This is used to study the risk of false positives:) - global miller_rabin_test_count - - miller_rabin_test_count = 0 - - if n <= smallprimes[-1]: - if n in smallprimes: return True - else: return False - - if gcd( n, 2*3*5*7*11 ) != 1: return False - - # Choose a number of iterations sufficient to reduce the - # probability of accepting a composite below 2**-80 - # (from Menezes et al. Table 4.4): - - t = 40 - n_bits = 1 + int( math.log( n, 2 ) ) - for k, tt in ( ( 100, 27 ), - ( 150, 18 ), - ( 200, 15 ), - ( 250, 12 ), - ( 300, 9 ), - ( 350, 8 ), - ( 400, 7 ), - ( 450, 6 ), - ( 550, 5 ), - ( 650, 4 ), - ( 850, 3 ), - ( 1300, 2 ), - ): - if n_bits < k: break - t = tt - - # Run the test t times: - - s = 0 - r = n - 1 - while ( r % 2 ) == 0: - s = s + 1 - r = r // 2 - for i in xrange( t ): - a = smallprimes[ i ] - y = modular_exp( a, r, n ) - if y != 1 and y != n-1: - j = 1 - while j <= s - 1 and y != n - 1: - y = modular_exp( y, 2, n ) - if y == 1: - miller_rabin_test_count = i + 1 - return False - j = j + 1 - if y != n-1: - miller_rabin_test_count = i + 1 - return False - return True - - -def next_prime( starting_value ): - "Return the smallest prime larger than the starting value." - - if starting_value < 2: return 2 - result = ( starting_value + 1 ) | 1 - while not is_prime( result ): result = result + 2 - return result - - -smallprimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, - 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, - 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, - 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, - 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, - 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, - 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, - 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, - 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, - 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, - 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, - 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, - 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, - 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, - 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, - 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, - 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, - 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, - 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, - 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229] - -miller_rabin_test_count = 0 - -def __main__(): - - # Making sure locally defined exceptions work: - # p = modular_exp( 2, -2, 3 ) - # p = square_root_mod_prime( 2, 3 ) - - - print "Testing gcd..." - assert gcd( 3*5*7, 3*5*11, 3*5*13 ) == 3*5 - assert gcd( [ 3*5*7, 3*5*11, 3*5*13 ] ) == 3*5 - assert gcd( 3 ) == 3 - - print "Testing lcm..." - assert lcm( 3, 5*3, 7*3 ) == 3*5*7 - assert lcm( [ 3, 5*3, 7*3 ] ) == 3*5*7 - assert lcm( 3 ) == 3 - - print "Testing next_prime..." - bigprimes = ( 999671, - 999683, - 999721, - 999727, - 999749, - 999763, - 999769, - 999773, - 999809, - 999853, - 999863, - 999883, - 999907, - 999917, - 999931, - 999953, - 999959, - 999961, - 999979, - 999983 ) - - for i in xrange( len( bigprimes ) - 1 ): - assert next_prime( bigprimes[i] ) == bigprimes[ i+1 ] - - error_tally = 0 - - # Test the square_root_mod_prime function: - - for p in smallprimes: - print "Testing square_root_mod_prime for modulus p = %d." % p - squares = [] - - for root in range( 0, 1+p//2 ): - sq = ( root * root ) % p - squares.append( sq ) - calculated = square_root_mod_prime( sq, p ) - if ( calculated * calculated ) % p != sq: - error_tally = error_tally + 1 - print "Failed to find %d as sqrt( %d ) mod %d. Said %d." % \ - ( root, sq, p, calculated ) - - for nonsquare in range( 0, p ): - if nonsquare not in squares: - try: - calculated = square_root_mod_prime( nonsquare, p ) - except SquareRootError: - pass - else: - error_tally = error_tally + 1 - print "Failed to report no root for sqrt( %d ) mod %d." % \ - ( nonsquare, p ) - - # Test the jacobi function: - for m in range( 3, 400, 2 ): - print "Testing jacobi for modulus m = %d." % m - if is_prime( m ): - squares = [] - for root in range( 1, m ): - if jacobi( root * root, m ) != 1: - error_tally = error_tally + 1 - print "jacobi( %d * %d, %d ) != 1" % ( root, root, m ) - squares.append( root * root % m ) - for i in range( 1, m ): - if not i in squares: - if jacobi( i, m ) != -1: - error_tally = error_tally + 1 - print "jacobi( %d, %d ) != -1" % ( i, m ) - else: # m is not prime. - f = factorization( m ) - for a in range( 1, m ): - c = 1 - for i in f: - c = c * jacobi( a, i[0] ) ** i[1] - if c != jacobi( a, m ): - error_tally = error_tally + 1 - print "%d != jacobi( %d, %d )" % ( c, a, m ) - - -# Test the inverse_mod function: - print "Testing inverse_mod . . ." - import random - n_tests = 0 - for i in range( 100 ): - m = random.randint( 20, 10000 ) - for j in range( 100 ): - a = random.randint( 1, m-1 ) - if gcd( a, m ) == 1: - n_tests = n_tests + 1 - inv = inverse_mod( a, m ) - if inv <= 0 or inv >= m or ( a * inv ) % m != 1: - error_tally = error_tally + 1 - print "%d = inverse_mod( %d, %d ) is wrong." % ( inv, a, m ) - assert n_tests > 1000 - print n_tests, " tests of inverse_mod completed." - - class FailedTest(Exception): pass - print error_tally, "errors detected." - if error_tally != 0: - raise FailedTest("%d errors detected" % error_tally) - -if __name__ == '__main__': - __main__() diff --git a/ecdsa/test_pyecdsa.py b/ecdsa/test_pyecdsa.py @@ -1,486 +0,0 @@ -import unittest -import os -import time -import shutil -import subprocess -from binascii import hexlify, unhexlify -from hashlib import sha1, sha256 - -from keys import SigningKey, VerifyingKey -from keys import BadSignatureError -import util -from util import sigencode_der, sigencode_strings -from util import sigdecode_der, sigdecode_strings -from curves import Curve, UnknownCurveError -from curves import NIST192p, NIST224p, NIST256p, NIST384p, NIST521p -import der - -class SubprocessError(Exception): - pass - -def run_openssl(cmd): - OPENSSL = "openssl" - p = subprocess.Popen([OPENSSL] + cmd.split(), - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - stdout, ignored = p.communicate() - if p.returncode != 0: - raise SubprocessError("cmd '%s %s' failed: rc=%s, stdout/err was %s" % - (OPENSSL, cmd, p.returncode, stdout)) - return stdout - -BENCH = False - -class ECDSA(unittest.TestCase): - def test_basic(self): - priv = SigningKey.generate() - pub = priv.get_verifying_key() - - data = "blahblah" - sig = priv.sign(data) - - self.failUnless(pub.verify(sig, data)) - self.failUnlessRaises(BadSignatureError, pub.verify, sig, data+"bad") - - pub2 = VerifyingKey.from_string(pub.to_string()) - self.failUnless(pub2.verify(sig, data)) - - def test_bad_usage(self): - # sk=SigningKey() is wrong - self.failUnlessRaises(TypeError, SigningKey) - self.failUnlessRaises(TypeError, VerifyingKey) - - def test_lengths(self): - default = NIST192p - priv = SigningKey.generate() - pub = priv.get_verifying_key() - self.failUnlessEqual(len(pub.to_string()), default.verifying_key_length) - sig = priv.sign("data") - self.failUnlessEqual(len(sig), default.signature_length) - if BENCH: - print - for curve in (NIST192p, NIST224p, NIST256p, NIST384p, NIST521p): - start = time.time() - priv = SigningKey.generate(curve=curve) - pub1 = priv.get_verifying_key() - keygen_time = time.time() - start - pub2 = VerifyingKey.from_string(pub1.to_string(), curve) - self.failUnlessEqual(pub1.to_string(), pub2.to_string()) - self.failUnlessEqual(len(pub1.to_string()), - curve.verifying_key_length) - start = time.time() - sig = priv.sign("data") - sign_time = time.time() - start - self.failUnlessEqual(len(sig), curve.signature_length) - if BENCH: - start = time.time() - pub1.verify(sig, "data") - verify_time = time.time() - start - print "%s: siglen=%d, keygen=%0.3fs, sign=%0.3f, verify=%0.3f" \ - % (curve.name, curve.signature_length, - keygen_time, sign_time, verify_time) - - def test_serialize(self): - seed = "secret" - curve = NIST192p - secexp1 = util.randrange_from_seed__trytryagain(seed, curve.order) - secexp2 = util.randrange_from_seed__trytryagain(seed, curve.order) - self.failUnlessEqual(secexp1, secexp2) - priv1 = SigningKey.from_secret_exponent(secexp1, curve) - priv2 = SigningKey.from_secret_exponent(secexp2, curve) - self.failUnlessEqual(hexlify(priv1.to_string()), - hexlify(priv2.to_string())) - self.failUnlessEqual(priv1.to_pem(), priv2.to_pem()) - pub1 = priv1.get_verifying_key() - pub2 = priv2.get_verifying_key() - data = "data" - sig1 = priv1.sign(data) - sig2 = priv2.sign(data) - self.failUnless(pub1.verify(sig1, data)) - self.failUnless(pub2.verify(sig1, data)) - self.failUnless(pub1.verify(sig2, data)) - self.failUnless(pub2.verify(sig2, data)) - self.failUnlessEqual(hexlify(pub1.to_string()), - hexlify(pub2.to_string())) - - def test_nonrandom(self): - s = "all the entropy in the entire world, compressed into one line" - def not_much_entropy(numbytes): - return s[:numbytes] - # we control the entropy source, these two keys should be identical: - priv1 = SigningKey.generate(entropy=not_much_entropy) - priv2 = SigningKey.generate(entropy=not_much_entropy) - self.failUnlessEqual(hexlify(priv1.get_verifying_key().to_string()), - hexlify(priv2.get_verifying_key().to_string())) - # likewise, signatures should be identical. Obviously you'd never - # want to do this with keys you care about, because the secrecy of - # the private key depends upon using different random numbers for - # each signature - sig1 = priv1.sign("data", entropy=not_much_entropy) - sig2 = priv2.sign("data", entropy=not_much_entropy) - self.failUnlessEqual(hexlify(sig1), hexlify(sig2)) - - def failUnlessPrivkeysEqual(self, priv1, priv2): - self.failUnlessEqual(priv1.privkey.secret_multiplier, - priv2.privkey.secret_multiplier) - self.failUnlessEqual(priv1.privkey.public_key.generator, - priv2.privkey.public_key.generator) - - def failIfPrivkeysEqual(self, priv1, priv2): - self.failIfEqual(priv1.privkey.secret_multiplier, - priv2.privkey.secret_multiplier) - - def test_privkey_creation(self): - s = "all the entropy in the entire world, compressed into one line" - def not_much_entropy(numbytes): - return s[:numbytes] - priv1 = SigningKey.generate() - self.failUnlessEqual(priv1.baselen, NIST192p.baselen) - - priv1 = SigningKey.generate(curve=NIST224p) - self.failUnlessEqual(priv1.baselen, NIST224p.baselen) - - priv1 = SigningKey.generate(entropy=not_much_entropy) - self.failUnlessEqual(priv1.baselen, NIST192p.baselen) - priv2 = SigningKey.generate(entropy=not_much_entropy) - self.failUnlessEqual(priv2.baselen, NIST192p.baselen) - self.failUnlessPrivkeysEqual(priv1, priv2) - - priv1 = SigningKey.from_secret_exponent(secexp=3) - self.failUnlessEqual(priv1.baselen, NIST192p.baselen) - priv2 = SigningKey.from_secret_exponent(secexp=3) - self.failUnlessPrivkeysEqual(priv1, priv2) - - priv1 = SigningKey.from_secret_exponent(secexp=4, curve=NIST224p) - self.failUnlessEqual(priv1.baselen, NIST224p.baselen) - - def test_privkey_strings(self): - priv1 = SigningKey.generate() - s1 = priv1.to_string() - self.failUnlessEqual(type(s1), str) - self.failUnlessEqual(len(s1), NIST192p.baselen) - priv2 = SigningKey.from_string(s1) - self.failUnlessPrivkeysEqual(priv1, priv2) - - s1 = priv1.to_pem() - self.failUnlessEqual(type(s1), str) - self.failUnless(s1.startswith("-----BEGIN EC PRIVATE KEY-----")) - self.failUnless(s1.strip().endswith("-----END EC PRIVATE KEY-----")) - priv2 = SigningKey.from_pem(s1) - self.failUnlessPrivkeysEqual(priv1, priv2) - - s1 = priv1.to_der() - self.failUnlessEqual(type(s1), str) - priv2 = SigningKey.from_der(s1) - self.failUnlessPrivkeysEqual(priv1, priv2) - - priv1 = SigningKey.generate(curve=NIST256p) - s1 = priv1.to_pem() - self.failUnlessEqual(type(s1), str) - self.failUnless(s1.startswith("-----BEGIN EC PRIVATE KEY-----")) - self.failUnless(s1.strip().endswith("-----END EC PRIVATE KEY-----")) - priv2 = SigningKey.from_pem(s1) - self.failUnlessPrivkeysEqual(priv1, priv2) - - s1 = priv1.to_der() - self.failUnlessEqual(type(s1), str) - priv2 = SigningKey.from_der(s1) - self.failUnlessPrivkeysEqual(priv1, priv2) - - def failUnlessPubkeysEqual(self, pub1, pub2): - self.failUnlessEqual(pub1.pubkey.point, pub2.pubkey.point) - self.failUnlessEqual(pub1.pubkey.generator, pub2.pubkey.generator) - self.failUnlessEqual(pub1.curve, pub2.curve) - - def test_pubkey_strings(self): - priv1 = SigningKey.generate() - pub1 = priv1.get_verifying_key() - s1 = pub1.to_string() - self.failUnlessEqual(type(s1), str) - self.failUnlessEqual(len(s1), NIST192p.verifying_key_length) - pub2 = VerifyingKey.from_string(s1) - self.failUnlessPubkeysEqual(pub1, pub2) - - priv1 = SigningKey.generate(curve=NIST256p) - pub1 = priv1.get_verifying_key() - s1 = pub1.to_string() - self.failUnlessEqual(type(s1), str) - self.failUnlessEqual(len(s1), NIST256p.verifying_key_length) - pub2 = VerifyingKey.from_string(s1, curve=NIST256p) - self.failUnlessPubkeysEqual(pub1, pub2) - - pub1_der = pub1.to_der() - self.failUnlessEqual(type(pub1_der), str) - pub2 = VerifyingKey.from_der(pub1_der) - self.failUnlessPubkeysEqual(pub1, pub2) - - self.failUnlessRaises(der.UnexpectedDER, - VerifyingKey.from_der, pub1_der+"junk") - badpub = VerifyingKey.from_der(pub1_der) - class FakeGenerator: - def order(self): return 123456789 - badcurve = Curve("unknown", None, FakeGenerator(), (1,2,3,4,5,6)) - badpub.curve = badcurve - badder = badpub.to_der() - self.failUnlessRaises(UnknownCurveError, VerifyingKey.from_der, badder) - - pem = pub1.to_pem() - self.failUnlessEqual(type(pem), str) - self.failUnless(pem.startswith("-----BEGIN PUBLIC KEY-----"), pem) - self.failUnless(pem.strip().endswith("-----END PUBLIC KEY-----"), pem) - pub2 = VerifyingKey.from_pem(pem) - self.failUnlessPubkeysEqual(pub1, pub2) - - def test_signature_strings(self): - priv1 = SigningKey.generate() - pub1 = priv1.get_verifying_key() - data = "data" - - sig = priv1.sign(data) - self.failUnlessEqual(type(sig), str) - self.failUnlessEqual(len(sig), NIST192p.signature_length) - self.failUnless(pub1.verify(sig, data)) - - sig = priv1.sign(data, sigencode=sigencode_strings) - self.failUnlessEqual(type(sig), tuple) - self.failUnlessEqual(len(sig), 2) - self.failUnlessEqual(type(sig[0]), str) - self.failUnlessEqual(type(sig[1]), str) - self.failUnlessEqual(len(sig[0]), NIST192p.baselen) - self.failUnlessEqual(len(sig[1]), NIST192p.baselen) - self.failUnless(pub1.verify(sig, data, sigdecode=sigdecode_strings)) - - sig_der = priv1.sign(data, sigencode=sigencode_der) - self.failUnlessEqual(type(sig_der), str) - self.failUnless(pub1.verify(sig_der, data, sigdecode=sigdecode_der)) - - def test_hashfunc(self): - sk = SigningKey.generate(curve=NIST256p, hashfunc=sha256) - data = "security level is 128 bits" - sig = sk.sign(data) - vk = VerifyingKey.from_string(sk.get_verifying_key().to_string(), - curve=NIST256p, hashfunc=sha256) - self.failUnless(vk.verify(sig, data)) - - sk2 = SigningKey.generate(curve=NIST256p) - sig2 = sk2.sign(data, hashfunc=sha256) - vk2 = VerifyingKey.from_string(sk2.get_verifying_key().to_string(), - curve=NIST256p, hashfunc=sha256) - self.failUnless(vk2.verify(sig2, data)) - - vk3 = VerifyingKey.from_string(sk.get_verifying_key().to_string(), - curve=NIST256p) - self.failUnless(vk3.verify(sig, data, hashfunc=sha256)) - - -class OpenSSL(unittest.TestCase): - # test interoperability with OpenSSL tools. Note that openssl's ECDSA - # sign/verify arguments changed between 0.9.8 and 1.0.0: the early - # versions require "-ecdsa-with-SHA1", the later versions want just - # "-SHA1" (or to leave out that argument entirely, which means the - # signature will use some default digest algorithm, probably determined - # by the key, probably always SHA1). - # - # openssl ecparam -name secp224r1 -genkey -out privkey.pem - # openssl ec -in privkey.pem -text -noout # get the priv/pub keys - # openssl dgst -ecdsa-with-SHA1 -sign privkey.pem -out data.sig data.txt - # openssl asn1parse -in data.sig -inform DER - # data.sig is 64 bytes, probably 56b plus ASN1 overhead - # openssl dgst -ecdsa-with-SHA1 -prverify privkey.pem -signature data.sig data.txt ; echo $? - # openssl ec -in privkey.pem -pubout -out pubkey.pem - # openssl ec -in privkey.pem -pubout -outform DER -out pubkey.der - - def get_openssl_messagedigest_arg(self): - v = run_openssl("version") - # e.g. "OpenSSL 1.0.0 29 Mar 2010", or "OpenSSL 1.0.0a 1 Jun 2010", - # or "OpenSSL 0.9.8o 01 Jun 2010" - vs = v.split()[1].split(".") - if vs >= ["1","0","0"]: - return "-SHA1" - else: - return "-ecdsa-with-SHA1" - - # sk: 1:OpenSSL->python 2:python->OpenSSL - # vk: 3:OpenSSL->python 4:python->OpenSSL - # sig: 5:OpenSSL->python 6:python->OpenSSL - - def test_from_openssl_nist192p(self): - return self.do_test_from_openssl(NIST192p, "prime192v1") - def test_from_openssl_nist224p(self): - return self.do_test_from_openssl(NIST224p, "secp224r1") - def test_from_openssl_nist384p(self): - return self.do_test_from_openssl(NIST384p, "secp384r1") - def test_from_openssl_nist521p(self): - return self.do_test_from_openssl(NIST521p, "secp521r1") - - def do_test_from_openssl(self, curve, curvename): - # OpenSSL: create sk, vk, sign. - # Python: read vk(3), checksig(5), read sk(1), sign, check - mdarg = self.get_openssl_messagedigest_arg() - if os.path.isdir("t"): - shutil.rmtree("t") - os.mkdir("t") - run_openssl("ecparam -name %s -genkey -out t/privkey.pem" % curvename) - run_openssl("ec -in t/privkey.pem -pubout -out t/pubkey.pem") - data = "data" - open("t/data.txt","wb").write(data) - run_openssl("dgst %s -sign t/privkey.pem -out t/data.sig t/data.txt" % mdarg) - run_openssl("dgst %s -verify t/pubkey.pem -signature t/data.sig t/data.txt" % mdarg) - pubkey_pem = open("t/pubkey.pem").read() - vk = VerifyingKey.from_pem(pubkey_pem) # 3 - sig_der = open("t/data.sig","rb").read() - self.failUnless(vk.verify(sig_der, data, # 5 - hashfunc=sha1, sigdecode=sigdecode_der)) - - sk = SigningKey.from_pem(open("t/privkey.pem").read()) # 1 - sig = sk.sign(data) - self.failUnless(vk.verify(sig, data)) - - def test_to_openssl_nist192p(self): - self.do_test_to_openssl(NIST192p, "prime192v1") - def test_to_openssl_nist224p(self): - self.do_test_to_openssl(NIST224p, "secp224r1") - def test_to_openssl_nist384p(self): - self.do_test_to_openssl(NIST384p, "secp384r1") - def test_to_openssl_nist521p(self): - self.do_test_to_openssl(NIST521p, "secp521r1") - - def do_test_to_openssl(self, curve, curvename): - # Python: create sk, vk, sign. - # OpenSSL: read vk(4), checksig(6), read sk(2), sign, check - mdarg = self.get_openssl_messagedigest_arg() - if os.path.isdir("t"): - shutil.rmtree("t") - os.mkdir("t") - sk = SigningKey.generate(curve=curve) - vk = sk.get_verifying_key() - data = "data" - open("t/pubkey.der","wb").write(vk.to_der()) # 4 - open("t/pubkey.pem","wb").write(vk.to_pem()) # 4 - sig_der = sk.sign(data, hashfunc=sha1, sigencode=sigencode_der) - open("t/data.sig","wb").write(sig_der) # 6 - open("t/data.txt","wb").write(data) - open("t/baddata.txt","wb").write(data+"corrupt") - - self.failUnlessRaises(SubprocessError, run_openssl, - "dgst %s -verify t/pubkey.der -keyform DER -signature t/data.sig t/baddata.txt" % mdarg) - run_openssl("dgst %s -verify t/pubkey.der -keyform DER -signature t/data.sig t/data.txt" % mdarg) - - open("t/privkey.pem","wb").write(sk.to_pem()) # 2 - run_openssl("dgst %s -sign t/privkey.pem -out t/data.sig2 t/data.txt" % mdarg) - run_openssl("dgst %s -verify t/pubkey.pem -signature t/data.sig2 t/data.txt" % mdarg) - -class DER(unittest.TestCase): - def test_oids(self): - oid_ecPublicKey = der.encode_oid(1, 2, 840, 10045, 2, 1) - self.failUnlessEqual(hexlify(oid_ecPublicKey), "06072a8648ce3d0201") - self.failUnlessEqual(hexlify(NIST224p.encoded_oid), "06052b81040021") - self.failUnlessEqual(hexlify(NIST256p.encoded_oid), - "06082a8648ce3d030107") - x = oid_ecPublicKey + "more" - x1, rest = der.remove_object(x) - self.failUnlessEqual(x1, (1, 2, 840, 10045, 2, 1)) - self.failUnlessEqual(rest, "more") - - def test_integer(self): - self.failUnlessEqual(der.encode_integer(0), "\x02\x01\x00") - self.failUnlessEqual(der.encode_integer(1), "\x02\x01\x01") - self.failUnlessEqual(der.encode_integer(127), "\x02\x01\x7f") - self.failUnlessEqual(der.encode_integer(128), "\x02\x02\x00\x80") - self.failUnlessEqual(der.encode_integer(256), "\x02\x02\x01\x00") - #self.failUnlessEqual(der.encode_integer(-1), "\x02\x01\xff") - - def s(n): return der.remove_integer(der.encode_integer(n) + "junk") - self.failUnlessEqual(s(0), (0, "junk")) - self.failUnlessEqual(s(1), (1, "junk")) - self.failUnlessEqual(s(127), (127, "junk")) - self.failUnlessEqual(s(128), (128, "junk")) - self.failUnlessEqual(s(256), (256, "junk")) - self.failUnlessEqual(s(1234567890123456789012345678901234567890), - ( 1234567890123456789012345678901234567890,"junk")) - - def test_number(self): - self.failUnlessEqual(der.encode_number(0), "\x00") - self.failUnlessEqual(der.encode_number(127), "\x7f") - self.failUnlessEqual(der.encode_number(128), "\x81\x00") - self.failUnlessEqual(der.encode_number(3*128+7), "\x83\x07") - #self.failUnlessEqual(der.read_number("\x81\x9b"+"more"), (155, 2)) - #self.failUnlessEqual(der.encode_number(155), "\x81\x9b") - for n in (0, 1, 2, 127, 128, 3*128+7, 840, 10045): #, 155): - x = der.encode_number(n) + "more" - n1, llen = der.read_number(x) - self.failUnlessEqual(n1, n) - self.failUnlessEqual(x[llen:], "more") - - def test_length(self): - self.failUnlessEqual(der.encode_length(0), "\x00") - self.failUnlessEqual(der.encode_length(127), "\x7f") - self.failUnlessEqual(der.encode_length(128), "\x81\x80") - self.failUnlessEqual(der.encode_length(255), "\x81\xff") - self.failUnlessEqual(der.encode_length(256), "\x82\x01\x00") - self.failUnlessEqual(der.encode_length(3*256+7), "\x82\x03\x07") - self.failUnlessEqual(der.read_length("\x81\x9b"+"more"), (155, 2)) - self.failUnlessEqual(der.encode_length(155), "\x81\x9b") - for n in (0, 1, 2, 127, 128, 255, 256, 3*256+7, 155): - x = der.encode_length(n) + "more" - n1, llen = der.read_length(x) - self.failUnlessEqual(n1, n) - self.failUnlessEqual(x[llen:], "more") - - def test_sequence(self): - x = der.encode_sequence("ABC", "DEF") + "GHI" - self.failUnlessEqual(x, "\x30\x06ABCDEFGHI") - x1, rest = der.remove_sequence(x) - self.failUnlessEqual(x1, "ABCDEF") - self.failUnlessEqual(rest, "GHI") - - def test_constructed(self): - x = der.encode_constructed(0, NIST224p.encoded_oid) - self.failUnlessEqual(hexlify(x), "a007" + "06052b81040021") - x = der.encode_constructed(1, unhexlify("0102030a0b0c")) - self.failUnlessEqual(hexlify(x), "a106" + "0102030a0b0c") - -class Util(unittest.TestCase): - def test_trytryagain(self): - tta = util.randrange_from_seed__trytryagain - for i in range(1000): - seed = "seed-%d" % i - for order in (2**8-2, 2**8-1, 2**8, 2**8+1, 2**8+2, - 2**16-1, 2**16+1): - n = tta(seed, order) - self.failUnless(1 <= n < order, (1, n, order)) - # this trytryagain *does* provide long-term stability - self.failUnlessEqual("%x"%(tta("seed", NIST224p.order)), - "6fa59d73bf0446ae8743cf748fc5ac11d5585a90356417e97155c3bc") - - def test_randrange(self): - # util.randrange does not provide long-term stability: we might - # change the algorithm in the future. - for i in range(1000): - entropy = util.PRNG("seed-%d" % i) - for order in (2**8-2, 2**8-1, 2**8, - 2**16-1, 2**16+1, - ): - # that oddball 2**16+1 takes half our runtime - n = util.randrange(order, entropy=entropy) - self.failUnless(1 <= n < order, (1, n, order)) - - def OFF_test_prove_uniformity(self): - order = 2**8-2 - counts = dict([(i, 0) for i in range(1, order)]) - assert 0 not in counts - assert order not in counts - for i in range(1000000): - seed = "seed-%d" % i - n = util.randrange_from_seed__trytryagain(seed, order) - counts[n] += 1 - # this technique should use the full range - self.failUnless(counts[order-1]) - for i in range(1, order): - print "%3d: %s" % (i, "*"*(counts[i]//100)) - - -def __main__(): - unittest.main() -if __name__ == "__main__": - __main__() diff --git a/ecdsa/util.py b/ecdsa/util.py @@ -1,215 +0,0 @@ - -import os -import math -import binascii -from hashlib import sha256 -import der -from curves import orderlen - -# RFC5480: -# The "unrestricted" algorithm identifier is: -# id-ecPublicKey OBJECT IDENTIFIER ::= { -# iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 } - -oid_ecPublicKey = (1, 2, 840, 10045, 2, 1) -encoded_oid_ecPublicKey = der.encode_oid(*oid_ecPublicKey) - -def randrange(order, entropy=None): - """Return a random integer k such that 1 <= k < order, uniformly - distributed across that range. For simplicity, this only behaves well if - 'order' is fairly close (but below) a power of 256. The try-try-again - algorithm we use takes longer and longer time (on average) to complete as - 'order' falls, rising to a maximum of avg=512 loops for the worst-case - (256**k)+1 . All of the standard curves behave well. There is a cutoff at - 10k loops (which raises RuntimeError) to prevent an infinite loop when - something is really broken like the entropy function not working. - - Note that this function is not declared to be forwards-compatible: we may - change the behavior in future releases. The entropy= argument (which - should get a callable that behaves like os.entropy) can be used to - achieve stability within a given release (for repeatable unit tests), but - should not be used as a long-term-compatible key generation algorithm. - """ - # we could handle arbitrary orders (even 256**k+1) better if we created - # candidates bit-wise instead of byte-wise, which would reduce the - # worst-case behavior to avg=2 loops, but that would be more complex. The - # change would be to round the order up to a power of 256, subtract one - # (to get 0xffff..), use that to get a byte-long mask for the top byte, - # generate the len-1 entropy bytes, generate one extra byte and mask off - # the top bits, then combine it with the rest. Requires jumping back and - # forth between strings and integers a lot. - - if entropy is None: - entropy = os.urandom - assert order > 1 - bytes = orderlen(order) - dont_try_forever = 10000 # gives about 2**-60 failures for worst case - while dont_try_forever > 0: - dont_try_forever -= 1 - candidate = string_to_number(entropy(bytes)) + 1 - if 1 <= candidate < order: - return candidate - continue - raise RuntimeError("randrange() tried hard but gave up, either something" - " is very wrong or you got realllly unlucky. Order was" - " %x" % order) - -class PRNG: - # this returns a callable which, when invoked with an integer N, will - # return N pseudorandom bytes. Note: this is a short-term PRNG, meant - # primarily for the needs of randrange_from_seed__trytryagain(), which - # only needs to run it a few times per seed. It does not provide - # protection against state compromise (forward security). - def __init__(self, seed): - self.generator = self.block_generator(seed) - - def __call__(self, numbytes): - return "".join([self.generator.next() for i in range(numbytes)]) - - def block_generator(self, seed): - counter = 0 - while True: - for byte in sha256("prng-%d-%s" % (counter, seed)).digest(): - yield byte - counter += 1 - -def randrange_from_seed__overshoot_modulo(seed, order): - # hash the data, then turn the digest into a number in [1,order). - # - # We use David-Sarah Hopwood's suggestion: turn it into a number that's - # sufficiently larger than the group order, then modulo it down to fit. - # This should give adequate (but not perfect) uniformity, and simple - # code. There are other choices: try-try-again is the main one. - base = PRNG(seed)(2*orderlen(order)) - number = (int(binascii.hexlify(base), 16) % (order-1)) + 1 - assert 1 <= number < order, (1, number, order) - return number - -def lsb_of_ones(numbits): - return (1 << numbits) - 1 -def bits_and_bytes(order): - bits = int(math.log(order-1, 2)+1) - bytes = bits // 8 - extrabits = bits % 8 - return bits, bytes, extrabits - -# the following randrange_from_seed__METHOD() functions take an -# arbitrarily-sized secret seed and turn it into a number that obeys the same -# range limits as randrange() above. They are meant for deriving consistent -# signing keys from a secret rather than generating them randomly, for -# example a protocol in which three signing keys are derived from a master -# secret. You should use a uniformly-distributed unguessable seed with about -# curve.baselen bytes of entropy. To use one, do this: -# seed = os.urandom(curve.baselen) # or other starting point -# secexp = ecdsa.util.randrange_from_seed__trytryagain(sed, curve.order) -# sk = SigningKey.from_secret_exponent(secexp, curve) - -def randrange_from_seed__truncate_bytes(seed, order, hashmod=sha256): - # hash the seed, then turn the digest into a number in [1,order), but - # don't worry about trying to uniformly fill the range. This will lose, - # on average, four bits of entropy. - bits, bytes, extrabits = bits_and_bytes(order) - if extrabits: - bytes += 1 - base = hashmod(seed).digest()[:bytes] - base = "\x00"*(bytes-len(base)) + base - number = 1+int(binascii.hexlify(base), 16) - assert 1 <= number < order - return number - -def randrange_from_seed__truncate_bits(seed, order, hashmod=sha256): - # like string_to_randrange_truncate_bytes, but only lose an average of - # half a bit - bits = int(math.log(order-1, 2)+1) - maxbytes = (bits+7) // 8 - base = hashmod(seed).digest()[:maxbytes] - base = "\x00"*(maxbytes-len(base)) + base - topbits = 8*maxbytes - bits - if topbits: - base = chr(ord(base[0]) & lsb_of_ones(topbits)) + base[1:] - number = 1+int(binascii.hexlify(base), 16) - assert 1 <= number < order - return number - -def randrange_from_seed__trytryagain(seed, order): - # figure out exactly how many bits we need (rounded up to the nearest - # bit), so we can reduce the chance of looping to less than 0.5 . This is - # specified to feed from a byte-oriented PRNG, and discards the - # high-order bits of the first byte as necessary to get the right number - # of bits. The average number of loops will range from 1.0 (when - # order=2**k-1) to 2.0 (when order=2**k+1). - assert order > 1 - bits, bytes, extrabits = bits_and_bytes(order) - generate = PRNG(seed) - while True: - extrabyte = "" - if extrabits: - extrabyte = chr(ord(generate(1)) & lsb_of_ones(extrabits)) - guess = string_to_number(extrabyte + generate(bytes)) + 1 - if 1 <= guess < order: - return guess - - -def number_to_string(num, order): - l = orderlen(order) - fmt_str = "%0" + str(2*l) + "x" - string = binascii.unhexlify(fmt_str % num) - assert len(string) == l, (len(string), l) - return string - -def string_to_number(string): - return int(binascii.hexlify(string), 16) - -def string_to_number_fixedlen(string, order): - l = orderlen(order) - assert len(string) == l, (len(string), l) - return int(binascii.hexlify(string), 16) - -# these methods are useful for the sigencode= argument to SK.sign() and the -# sigdecode= argument to VK.verify(), and control how the signature is packed -# or unpacked. - -def sigencode_strings(r, s, order): - r_str = number_to_string(r, order) - s_str = number_to_string(s, order) - return (r_str, s_str) - -def sigencode_string(r, s, order): - # for any given curve, the size of the signature numbers is - # fixed, so just use simple concatenation - r_str, s_str = sigencode_strings(r, s, order) - return r_str + s_str - -def sigencode_der(r, s, order): - return der.encode_sequence(der.encode_integer(r), der.encode_integer(s)) - - -def sigdecode_string(signature, order): - l = orderlen(order) - assert len(signature) == 2*l, (len(signature), 2*l) - r = string_to_number_fixedlen(signature[:l], order) - s = string_to_number_fixedlen(signature[l:], order) - return r, s - -def sigdecode_strings(rs_strings, order): - (r_str, s_str) = rs_strings - l = orderlen(order) - assert len(r_str) == l, (len(r_str), l) - assert len(s_str) == l, (len(s_str), l) - r = string_to_number_fixedlen(r_str, order) - s = string_to_number_fixedlen(s_str, order) - return r, s - -def sigdecode_der(sig_der, order): - #return der.encode_sequence(der.encode_integer(r), der.encode_integer(s)) - rs_strings, empty = der.remove_sequence(sig_der) - if empty != "": - raise der.UnexpectedDER("trailing junk after DER sig: %s" % - binascii.hexlify(empty)) - r, rest = der.remove_integer(rs_strings) - s, empty = der.remove_integer(rest) - if empty != "": - raise der.UnexpectedDER("trailing junk after DER numbers: %s" % - binascii.hexlify(empty)) - return r, s - diff --git a/electrum b/electrum @@ -39,50 +39,49 @@ from optparse import OptionParser from decimal import Decimal known_commands = { - 'help':'print help', - 'validateaddress':'check that the address is valid', - 'balance': "Display the balance of your wallet or of an address.\nsyntax: balance [<address>]", + 'help':'Prints this help', + 'validateaddress':'Check that the address is valid', + 'balance': "Display the balance of your wallet or of an address.\nSyntax: balance [<address>]", 'contacts': "Show your list of contacts", - 'create':'create wallet', - 'restore':'restore wallet', - 'payto':""" - payto <recipient> <amount> [label] - create and broadcast a transaction. - <recipient> can be a bitcoin address or a label - options:\n--fee, -f: set transaction fee\n--fromaddr, -s: send from address -\n--changeaddr, -c: send change to address + 'create':'Create a wallet', + 'restore':'Restore a wallet', + 'payto':"""Create and broadcast a transaction. +Syntax: payto <recipient> <amount> [label] +<recipient> can be a bitcoin address or a label +options:\n --fee, -f: set transaction fee\n --fromaddr, -s: send from address -\n --changeaddr, -c: send change to address """, 'sendtx': - """sendtx <tx> - broadcast a transaction to the network. <tx> must be in hexadecimal""", + 'Broadcasts a transaction to the network. \nSyntax: sendtx <tx>\n<tx> must be in hexadecimal.', 'password': - "change your password", + "Changes your password", 'addresses': - """show your list of addresses. - options: - -a: show all addresses, including change addresses - -k: show private keys - -b: show the balance of addresses""", - 'history':"show the transaction history", - 'label':"assign a label to an item", + """Shows your list of addresses. +options: + -a: show all addresses, including change addresses + -k: show private keys + -b: show the balance of addresses""", + + 'history':"Shows the transaction history", + 'label':'Assign a label to an item\nSyntax: label <tx_hash> <label>', 'mktx': - """create a signed transaction. password protected - syntax: mktx <recipient> <amount> [label] - options:\n--fee, -f: set transaction fee\n--fromaddr, -s: send from address -\n--changeaddr, -c: send change to address + """Create a signed transaction, password protected. +Syntax: mktx <recipient> <amount> [label] +options:\n --fee, -f: set transaction fee\n --fromaddr, -s: send from address -\n --changeaddr, -c: send change to address """, 'seed': - "print the generation seed of your wallet.", + "Print the generation seed of your wallet.", 'import': - "import key pair", + 'Imports a key pair\nSyntax: import <address>:<privatekey>', 'signmessage': - 'sign a message with a key', + 'Signs a message with a key\nSyntax: signmessage <address> <message>', 'verifymessage': - 'verify signature', + 'Verifies a signature\nSyntax: verifymessage <address> <signature> <message>', 'eval': "Run python eval() on an object\nSyntax: eval <expression>\nExample: eval \"wallet.aliases\"", 'deseed': - "remove seed from the wallet. The seed is stored in a file that has the name of the wallet plus '.seed'", + "Remove seed from the wallet. The seed is stored in a file that has the name of the wallet plus '.seed'", 'reseed': - "restore seed of the wallet. The wallet must have no seed, and the seed must match the wallet's master public key.", + "Restore seed of the wallet. The wallet must have no seed, and the seed must match the wallet's master public key.", 'freeze':'', 'unfreeze':'', 'prioritize':'', @@ -495,9 +494,14 @@ if __name__ == '__main__': print wallet.sign_message(address, message, password) elif cmd == 'verifymessage': - address = args[1] - signature = args[2] - message = ' '.join(args[3:]) + try: + address = args[1] + signature = args[2] + message = ' '.join(args[3:]) + except: + print "Not all parameters were given, displaying help instead." + print known_commands[cmd] + sys.exit(1) if len(args) > 4: print "Warning: Message was reconstructed from several arguments:", repr(message) try: diff --git a/get_history b/get_history @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +import sys +from electrum import TcpStratumInterface + +try: + addr = sys.argv[1] +except: + print "usage: get_history <bitcoin_address>" + sys.exit(1) + +i = TcpStratumInterface('ecdsa.org', 50001) +i.init_socket() +i.start() +i.send([('blockchain.address.get_history',[addr])]) + +while True: + try: + r = i.responses.get(True, 100000000000) + except KeyboardInterrupt: + break + method = r.get('method') + if method == 'blockchain.address.get_history': + confirmed = unconfirmed = 0 + h = r.get('result') + for item in h: + print item['tx_hash'], item['value'] + + break diff --git a/lib/gui_qt.py b/lib/gui_qt.py @@ -45,7 +45,14 @@ import bmp, mnemonic, pyqrnative from decimal import Decimal import platform -MONOSPACE_FONT = 'Lucida Console' if platform.system() == 'Windows' else 'monospace' + +if platform.system() == 'Windows': + MONOSPACE_FONT = 'Lucida Console' +elif platform.system() == 'Darwin': + MONOSPACE_FONT = 'Monaco' +else: + MONOSPACE_FONT = 'monospace' + ALIAS_REGEXP = '^(|([\w\-\.]+)@)((\w[\w\-]+\.)+[\w\-]+)$' def numbify(entry, is_int = False): @@ -80,6 +87,7 @@ class Timer(QtCore.QThread): class HelpButton(QPushButton): def __init__(self, text): QPushButton.__init__(self, '?') + self.setFocusPolicy(Qt.NoFocus) self.setFixedWidth(20) self.clicked.connect(lambda: QMessageBox.information(self, 'Help', text, 'OK') ) @@ -209,6 +217,12 @@ class ElectrumWindow(QMainWindow): self.connect(self, QtCore.SIGNAL('updatesignal'), self.update_wallet) self.history_list.setFocus(True) + # dark magic fix by flatfly; https://bitcointalk.org/index.php?topic=73651.msg959913#msg959913 + if platform.system() == 'Windows': + n = 3 if self.wallet.seed else 2 + tabs.setCurrentIndex (n) + tabs.setCurrentIndex (0) + def connect_slots(self, sender): if self.wallet.seed: @@ -429,7 +443,7 @@ class ElectrumWindow(QMainWindow): self.payto_e = QLineEdit() grid.addWidget(QLabel(_('Pay to')), 1, 0) grid.addWidget(self.payto_e, 1, 1, 1, 3) - grid.addWidget(HelpButton('Recipient of the funds.\n\nYou may enter a Bitcoin address, a label from your list of contacts (a list of completions will be proposed), or an alias (email-like address that forwards to a Bitcoin address)'), 1, 4) + grid.addWidget(HelpButton(_('Recipient of the funds.') + '\n\n' + _('You may enter a Bitcoin address, a label from your list of contacts (a list of completions will be proposed), or an alias (email-like address that forwards to a Bitcoin address)')), 1, 4) completer = QCompleter() completer.setCaseSensitivity(False) @@ -439,31 +453,31 @@ class ElectrumWindow(QMainWindow): self.message_e = QLineEdit() grid.addWidget(QLabel(_('Description')), 2, 0) grid.addWidget(self.message_e, 2, 1, 1, 3) - grid.addWidget(HelpButton('Description of the transaction (not mandatory).\n\nThe description is not sent to the recipient of the funds. It is stored in your wallet file, and displayed in the \'History\' tab.'), 2, 4) + grid.addWidget(HelpButton(_('Description of the transaction (not mandatory).') + '\n\n' + _('The description is not sent to the recipient of the funds. It is stored in your wallet file, and displayed in the \'History\' tab.')), 2, 4) self.amount_e = QLineEdit() grid.addWidget(QLabel(_('Amount')), 3, 0) grid.addWidget(self.amount_e, 3, 1, 1, 2) - grid.addWidget(HelpButton('Amount to be sent.\n\nThe amount will be displayed in red if you do not have enough funds in your wallet. Note that if you have frozen some of your addresses, the available funds will be lower than your total balance.'), 3, 3) + grid.addWidget(HelpButton( + _('Amount to be sent.') + '\n\n' \ + + _('The amount will be displayed in red if you do not have enough funds in your wallet. Note that if you have frozen some of your addresses, the available funds will be lower than your total balance.')), 3, 3) - self.nochange_cb = QCheckBox('Do not create change address') - grid.addWidget(self.nochange_cb,3,3) - self.nochange_cb.setChecked(False) - self.nochange_cb.setHidden(not self.wallet.expert_mode) - self.fee_e = QLineEdit() grid.addWidget(QLabel(_('Fee')), 4, 0) grid.addWidget(self.fee_e, 4, 1, 1, 2) - grid.addWidget(HelpButton('Bitcoin transactions are in general not free. A transaction fee is paid by the sender of the funds.\n\nThe amount of fee can be decided freely by the sender. However, transactions with low fees take more time to be processed.\n\nThe fee suggested by this software increases with the size of the transaction.'), 4, 3) - + grid.addWidget(HelpButton( + _('Bitcoin transactions are in general not free. A transaction fee is paid by the sender of the funds.') + '\n\n'\ + + _('The amount of fee can be decided freely by the sender. However, transactions with low fees take more time to be processed.') + '\n\n'\ + + _('A suggested fee is automatically added to this field. You may override it. The suggested fee increases with the size of the transaction.')), 4, 3) + b = EnterButton(_("Send"), self.do_send) - grid.addWidget(b, 5, 1) + grid.addWidget(b, 6, 1) b = EnterButton(_("Clear"),self.do_clear) - grid.addWidget(b, 5, 2) + grid.addWidget(b, 6, 2) self.payto_sig = QLabel('') - grid.addWidget(self.payto_sig, 6, 0, 1, 4) + grid.addWidget(self.payto_sig, 7, 0, 1, 4) QShortcut(QKeySequence("Up"), w, w.focusPreviousChild) QShortcut(QKeySequence("Down"), w, w.focusNextChild) @@ -555,15 +569,8 @@ class ElectrumWindow(QMainWindow): else: password = None - if self.nochange_cb.isChecked(): - inputs, total, fee = self.wallet.choose_tx_inputs( amount, fee ) - change_addr = inputs[0][0] - print "sending change to", change_addr - else: - change_addr = None - try: - tx = self.wallet.mktx( to_address, amount, label, password, fee, change_addr ) + tx = self.wallet.mktx( to_address, amount, label, password, fee) except BaseException, e: self.show_message(str(e)) return @@ -773,14 +780,13 @@ class ElectrumWindow(QMainWindow): for item in h: if not item['is_input'] : n=n+1 + tx = "%d "%n if n==0: - tx = "None" if address in self.wallet.addresses: gap += 1 if gap > self.wallet.gap_limit: is_red = True else: - tx = "%d"%n if address in self.wallet.addresses: gap = 0 @@ -836,7 +842,7 @@ class ElectrumWindow(QMainWindow): n = 0 for item in self.wallet.tx_history.values(): if address in item['outputs'] : n=n+1 - tx = "None" if n==0 else "%d"%n + tx = "%d"%n item = QTreeWidgetItem( [ address, label, tx] ) item.setFont(0, QFont(MONOSPACE_FONT)) l.addTopLevelItem(item) @@ -1158,7 +1164,8 @@ class ElectrumWindow(QMainWindow): self.wallet.save() self.update_receive_tab() self.update_contacts_tab() - self.nochange_cb.setHidden(not self.wallet.expert_mode) + # if self.wallet.seed: + # self.nochange_cb.setHidden(not self.wallet.expert_mode) def settings_dialog(self): @@ -1182,34 +1189,44 @@ class ElectrumWindow(QMainWindow): fee_e.setText("%s"% str( Decimal( self.wallet.fee)/100000000 ) ) grid.addWidget(QLabel(_('Transaction fee')), 2, 0) grid.addWidget(fee_e, 2, 1) - grid.addWidget(HelpButton('Fee per transaction input. Transactions involving multiple inputs tend to require a higher fee. Recommended value: 0.001'), 2, 2) + msg = _('Fee per transaction input. Transactions involving multiple inputs tend to require a higher fee.') + ' ' \ + + _('Recommended value') + ': 0.001' + grid.addWidget(HelpButton(msg), 2, 2) fee_e.textChanged.connect(lambda: numbify(fee_e,False)) nz_e = QLineEdit() nz_e.setText("%d"% self.wallet.num_zeros) grid.addWidget(QLabel(_('Display zeros')), 3, 0) - grid.addWidget(HelpButton('Number of zeros displayed after the decimal point. For example, if this is set to 2, "1." will be displayed as "1.00"'), 3, 2) + msg = _('Number of zeros displayed after the decimal point. For example, if this is set to 2, "1." will be displayed as "1.00"') + grid.addWidget(HelpButton(msg), 3, 2) grid.addWidget(nz_e, 3, 1) nz_e.textChanged.connect(lambda: numbify(nz_e,True)) + cb = QCheckBox(_('Expert mode')) + grid.addWidget(cb, 4, 0) + cb.setChecked(self.wallet.expert_mode) + if self.wallet.expert_mode: + + usechange_cb = QCheckBox(_('Use change addresses')) + grid.addWidget(usechange_cb, 5, 0) + usechange_cb.setChecked(self.wallet.use_change) + grid.addWidget(HelpButton(_('Using a change addresses makes it more difficult for other people to track your transactions. ')), 5, 2) + msg = _('The gap limit is the maximal number of contiguous unused addresses in your sequence of receiving addresses.') + '\n' \ + _('You may increase it if you need more receiving addresses.') + '\n\n' \ - + _('Your current gap limit is: ') + '%d'%self.wallet.gap_limit + '\n' \ + + _('Your current gap limit is') + ': %d'%self.wallet.gap_limit + '\n' \ + _('Given the current status of your address sequence, the minimum gap limit you can use is: ') + '%d'%self.wallet.min_acceptable_gap() + '\n\n' \ - + _('Warning:') + ' ' \ + + _('Warning') + ': ' \ + _('The gap limit parameter must be provided in order to recover your wallet from seed.') + ' ' \ + _('Do not modify it if you do not understand what you are doing, or if you expect to recover your wallet without knowing it!') + '\n\n' gap_e = QLineEdit() gap_e.setText("%d"% self.wallet.gap_limit) - grid.addWidget(QLabel(_('Gap limit')), 4, 0) - grid.addWidget(gap_e, 4, 1) - grid.addWidget(HelpButton(msg), 4, 2) + grid.addWidget(QLabel(_('Gap limit')), 6, 0) + grid.addWidget(gap_e, 6, 1) + grid.addWidget(HelpButton(msg), 6, 2) gap_e.textChanged.connect(lambda: numbify(nz_e,True)) - cb = QCheckBox('Expert mode') - grid.addWidget(cb, 5, 0) - cb.setChecked(self.wallet.expert_mode) vbox.addLayout(ok_cancel_buttons(d)) d.setLayout(vbox) @@ -1243,17 +1260,20 @@ class ElectrumWindow(QMainWindow): self.wallet.save() if self.wallet.expert_mode: + + self.wallet.use_change = usechange_cb.isChecked() + try: n = int(gap_e.text()) except: - QMessageBox.warning(self, _('Error'), _('Invalid Value'), _('OK')) + QMessageBox.warning(self, _('Error'), _('Invalid value'), _('OK')) return if self.wallet.gap_limit != n: r = self.wallet.change_gap_limit(n) if r: self.update_receive_tab() else: - QMessageBox.warning(self, _('Error'), _('Invalid Value'), _('OK')) + QMessageBox.warning(self, _('Error'), _('Invalid value'), _('OK')) self.set_expert_mode(cb.isChecked()) diff --git a/lib/interface.py b/lib/interface.py @@ -23,16 +23,29 @@ import threading, traceback, sys, time, json, Queue from version import ELECTRUM_VERSION DEFAULT_TIMEOUT = 5 -DEFAULT_SERVERS = [ 'ecdsa.org:50001:t', 'electrum.novit.ro:50001:t', 'electrum.bitcoins.sk:50001:t'] # list of default servers - - -def old_to_new(s): - s = s.replace("'blk_hash'", "'block_hash'") - s = s.replace("'pos'", "'index'") - s = s.replace("'nTime'", "'timestamp'") - s = s.replace("'is_in'", "'is_input'") - s = s.replace("'raw_scriptPubKey'","'raw_output_script'") - return s +DEFAULT_SERVERS = [ 'ecdsa.org:50001:t', + 'electrum.novit.ro:50001:t', + 'uncle-enzo.info:50001:t', + 'electrum.bytesized-hosting.com:50000:t'] # list of default servers + + +def replace_keys(obj, old_key, new_key): + if isinstance(obj, dict): + if old_key in obj: + obj[new_key] = obj[old_key] + del obj[old_key] + for elem in obj.itervalues(): + replace_keys(elem, old_key, new_key) + elif isinstance(obj, list): + for elem in obj: + replace_keys(elem, old_key, new_key) + +def old_to_new(d): + replace_keys(d, 'blk_hash', 'block_hash') + replace_keys(d, 'pos', 'index') + replace_keys(d, 'nTime', 'timestamp') + replace_keys(d, 'is_in', 'is_input') + replace_keys(d, 'raw_scriptPubKey', 'raw_output_script') class Interface(threading.Thread): @@ -330,11 +343,14 @@ class WalletSynchronizer(threading.Thread): s = [] host = item[1] ports = [] + version = None if len(item)>2: for v in item[2]: if re.match("[th]\d+",v): ports.append((v[0],v[1:])) - if ports: + if re.match("v(.?)+",v): + version = v[1:] + if ports and version: servers.append( (host, ports) ) self.interface.servers = servers @@ -353,6 +369,7 @@ class WalletSynchronizer(threading.Thread): elif method == 'blockchain.numblocks.subscribe': self.wallet.blocks = result + self.wallet.was_updated = True elif method == 'server.version': pass diff --git a/lib/version.py b/lib/version.py @@ -1,3 +1,3 @@ -ELECTRUM_VERSION = "0.58" +ELECTRUM_VERSION = "0.60" SEED_VERSION = 4 # bump this everytime the seed generation is modified -TRANSLATION_ID = 27601 # version of the wiki page +TRANSLATION_ID = 28079 # version of the wiki page diff --git a/lib/wallet.py b/lib/wallet.py @@ -256,6 +256,7 @@ class Wallet: self.gui_callback = gui_callback self.gap_limit = 5 # configuration + self.use_change = True self.fee = 100000 self.num_zeros = 0 self.master_public_key = '' @@ -611,6 +612,7 @@ class Wallet: s = { 'seed_version':self.seed_version, 'use_encryption':self.use_encryption, + 'use_change':self.use_change, 'master_public_key': self.master_public_key.encode('hex'), 'fee':self.fee, 'server':self.server, @@ -647,12 +649,13 @@ class Wallet: f.close() except: return - data = interface.old_to_new(data) try: d = ast.literal_eval( data ) + interface.old_to_new(d) self.seed_version = d.get('seed_version') self.master_public_key = d.get('master_public_key').decode('hex') self.use_encryption = d.get('use_encryption') + self.use_change = bool(d.get('use_change',True)) self.fee = int( d.get('fee') ) self.seed = d.get('seed') self.server = d.get('server') @@ -884,6 +887,11 @@ class Wallet: inputs, total, fee = self.choose_tx_inputs( amount, fee, from_addr ) if not inputs: raise BaseException("Not enough funds") + + if not self.use_change and not change_addr: + change_addr = inputs[0][0] + print "sending change to", change_addr + outputs = self.choose_tx_outputs( to_address, amount, fee, total, change_addr ) s_inputs = self.sign_inputs( inputs, outputs, password ) diff --git a/mki18n.py b/mki18n.py @@ -28,7 +28,7 @@ if not os.path.exists('locale'): os.mkdir('locale') -cmd = 'xgettext -s --no-wrap --omit-header -f app.fil --output=locale/messages.pot' +cmd = 'xgettext -s --no-wrap -f app.fil --output=locale/messages.pot' print cmd os.system(cmd) diff --git a/peers b/peers @@ -3,6 +3,7 @@ from electrum import TcpStratumInterface i = TcpStratumInterface('ecdsa.org', 50001) +i.init_socket() i.start() i.send([('server.peers.subscribe',[])]) diff --git a/setup.py b/setup.py @@ -12,7 +12,7 @@ if sys.version_info[:3] < (2,6,0): data_files = [] -if platform.system() != 'Windows': +if platform.system() != 'Windows' and platform.system() != 'Darwin': data_files += [ ('/usr/share/applications/',['electrum.desktop']), ('/usr/share/app-install/icons/',['electrum.png']) @@ -42,6 +42,7 @@ setup(name = "Electrum", 'electrum.i18n'], description = "Lightweight Bitcoin Wallet", author = "thomasv", + author_email = "thomasv@gitorious", license = "GNU GPLv3", url = "http://ecdsa/electrum", long_description = """Lightweight Bitcoin Wallet""" diff --git a/watch_address b/watch_address @@ -7,6 +7,7 @@ try: addr = sys.argv[1] except: print "usage: watch_address <bitcoin_address>" + sys.exit(1) i = TcpStratumInterface('ecdsa.org', 50001) i.init_socket()