From 48516e0fcb8d07d02da6ecb0c07f6b9a1948fe5c Mon Sep 17 00:00:00 2001 From: thomasv Date: Wed, 13 Jun 2012 09:38:36 +0200 Subject: [PATCH 01/34] re-removing aes ecdsa --- aes/__init__.py | 656 ----------------------------------------- ecdsa/__init__.py | 16 - ecdsa/curves.py | 41 --- ecdsa/der.py | 190 ------------ ecdsa/ecdsa.py | 560 ----------------------------------- ecdsa/ellipticcurve.py | 290 ------------------ ecdsa/keys.py | 252 ---------------- ecdsa/numbertheory.py | 614 -------------------------------------- ecdsa/test_pyecdsa.py | 486 ------------------------------ ecdsa/util.py | 215 -------------- 10 files changed, 3320 deletions(-) delete mode 100644 aes/__init__.py delete mode 100644 ecdsa/__init__.py delete mode 100644 ecdsa/curves.py delete mode 100644 ecdsa/der.py delete mode 100644 ecdsa/ecdsa.py delete mode 100644 ecdsa/ellipticcurve.py delete mode 100644 ecdsa/keys.py delete mode 100644 ecdsa/numbertheory.py delete mode 100644 ecdsa/test_pyecdsa.py delete mode 100644 ecdsa/util.py diff --git a/aes/__init__.py b/aes/__init__.py deleted file mode 100644 index e5f9e89a3..000000000 --- a/aes/__init__.py +++ /dev/null @@ -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/ecdsa/__init__.py b/ecdsa/__init__.py deleted file mode 100644 index 0ba98be3e..000000000 --- a/ecdsa/__init__.py +++ /dev/null @@ -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 deleted file mode 100644 index 2e4cc2cdb..000000000 --- a/ecdsa/curves.py +++ /dev/null @@ -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 deleted file mode 100644 index e03ad9c11..000000000 --- a/ecdsa/der.py +++ /dev/null @@ -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 deleted file mode 100644 index b9d1f311c..000000000 --- a/ecdsa/ecdsa.py +++ /dev/null @@ -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 deleted file mode 100644 index c1eb3616c..000000000 --- a/ecdsa/ellipticcurve.py +++ /dev/null @@ -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 deleted file mode 100644 index 29a1cd75b..000000000 --- a/ecdsa/keys.py +++ /dev/null @@ -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 deleted file mode 100644 index a07fb57be..000000000 --- a/ecdsa/numbertheory.py +++ /dev/null @@ -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 deleted file mode 100644 index 1f1a9bd7e..000000000 --- a/ecdsa/test_pyecdsa.py +++ /dev/null @@ -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 deleted file mode 100644 index 6d37891f9..000000000 --- a/ecdsa/util.py +++ /dev/null @@ -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 - From e4787600a1355e011feb67439b8bf35fd80bd530 Mon Sep 17 00:00:00 2001 From: thomasv Date: Wed, 13 Jun 2012 11:38:54 +0200 Subject: [PATCH 02/34] nofocus for help buttons --- lib/gui_qt.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/gui_qt.py b/lib/gui_qt.py index 3138d1afa..a09c4ae6a 100644 --- a/lib/gui_qt.py +++ b/lib/gui_qt.py @@ -80,6 +80,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') ) From 87f9fb611bb9f530e6c5ae0e4c5db8e581f0ac42 Mon Sep 17 00:00:00 2001 From: thomasv Date: Wed, 13 Jun 2012 11:45:29 +0200 Subject: [PATCH 03/34] gettext for help messages --- lib/gui_qt.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/gui_qt.py b/lib/gui_qt.py index a09c4ae6a..25a755abe 100644 --- a/lib/gui_qt.py +++ b/lib/gui_qt.py @@ -430,7 +430,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\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) completer = QCompleter() completer.setCaseSensitivity(False) @@ -440,14 +440,14 @@ 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\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) 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\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) - self.nochange_cb = QCheckBox('Do not create change address') + 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) @@ -455,7 +455,7 @@ class ElectrumWindow(QMainWindow): 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\nThe amount of fee can be decided freely by the sender. However, transactions with low fees take more time to be processed.\n\nA 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) @@ -1183,13 +1183,13 @@ 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) + grid.addWidget(HelpButton(_('Fee per transaction input. Transactions involving multiple inputs tend to require a higher fee. Recommended value: 0.001')), 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) + 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) grid.addWidget(nz_e, 3, 1) nz_e.textChanged.connect(lambda: numbify(nz_e,True)) @@ -1208,7 +1208,7 @@ class ElectrumWindow(QMainWindow): grid.addWidget(HelpButton(msg), 4, 2) gap_e.textChanged.connect(lambda: numbify(nz_e,True)) - cb = QCheckBox('Expert mode') + cb = QCheckBox(_('Expert mode')) grid.addWidget(cb, 5, 0) cb.setChecked(self.wallet.expert_mode) From 7d3386c345eb78507cd84710cd8435c71db0b810 Mon Sep 17 00:00:00 2001 From: thomasv Date: Wed, 13 Jun 2012 11:51:01 +0200 Subject: [PATCH 04/34] move nochange button to avoid conflict --- lib/gui_qt.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/gui_qt.py b/lib/gui_qt.py index 25a755abe..2a1012dca 100644 --- a/lib/gui_qt.py +++ b/lib/gui_qt.py @@ -448,7 +448,7 @@ class ElectrumWindow(QMainWindow): 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) self.nochange_cb = QCheckBox(_('Do not create change address')) - grid.addWidget(self.nochange_cb,3,3) + grid.addWidget(self.nochange_cb,5,1,1,4) self.nochange_cb.setChecked(False) self.nochange_cb.setHidden(not self.wallet.expert_mode) @@ -458,13 +458,13 @@ class ElectrumWindow(QMainWindow): 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\nA 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) From eb706ed5c4216ab92e6dec1a5055a794b7e0c973 Mon Sep 17 00:00:00 2001 From: thomasv Date: Wed, 13 Jun 2012 11:54:40 +0200 Subject: [PATCH 05/34] fix widget order --- lib/gui_qt.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/gui_qt.py b/lib/gui_qt.py index 2a1012dca..f17809345 100644 --- a/lib/gui_qt.py +++ b/lib/gui_qt.py @@ -447,16 +447,16 @@ class ElectrumWindow(QMainWindow): 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) - self.nochange_cb = QCheckBox(_('Do not create change address')) - grid.addWidget(self.nochange_cb,5,1,1,4) - 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\nA suggested fee is automatically added to this field. You may override it. The suggested fee increases with the size of the transaction.')), 4, 3) + self.nochange_cb = QCheckBox(_('Do not create change address')) + grid.addWidget(self.nochange_cb,5,1,1,4) + self.nochange_cb.setChecked(False) + self.nochange_cb.setHidden(not self.wallet.expert_mode) + b = EnterButton(_("Send"), self.do_send) grid.addWidget(b, 6, 1) From a5aa67c66e60d130a0ec825de2a7cb9aceb629df Mon Sep 17 00:00:00 2001 From: ThomasV Date: Wed, 13 Jun 2012 20:46:31 +0200 Subject: [PATCH 06/34] fix for watching-only wallets --- lib/gui_qt.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/gui_qt.py b/lib/gui_qt.py index f17809345..20de111e9 100644 --- a/lib/gui_qt.py +++ b/lib/gui_qt.py @@ -1159,7 +1159,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): From b39289c4dfe05fc649c9ce4fc1bf51f95b7eaaa3 Mon Sep 17 00:00:00 2001 From: ThomasV Date: Wed, 13 Jun 2012 21:12:16 +0200 Subject: [PATCH 07/34] patch by Soultaker; fix old_to_new --- lib/interface.py | 24 +++++++++++++++++------- lib/wallet.py | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/interface.py b/lib/interface.py index 710f7d87f..0e35f6259 100644 --- a/lib/interface.py +++ b/lib/interface.py @@ -26,13 +26,23 @@ 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 +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): diff --git a/lib/wallet.py b/lib/wallet.py index 6b15ddc24..5517fd5a6 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -647,9 +647,9 @@ 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') From 17cbb3fec03137fdf6e87540d4e151bffa694010 Mon Sep 17 00:00:00 2001 From: ThomasV Date: Thu, 14 Jun 2012 16:45:07 +0200 Subject: [PATCH 08/34] show 'used' column in receive tab --- lib/gui_qt.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/gui_qt.py b/lib/gui_qt.py index 20de111e9..c87e71104 100644 --- a/lib/gui_qt.py +++ b/lib/gui_qt.py @@ -658,7 +658,7 @@ class ElectrumWindow(QMainWindow): def create_receive_tab(self): - l,w,hbox = self.create_list_tab([_('Flags'), _('Address'), _('Label'), _('Balance'), _('Tx')]) + l,w,hbox = self.create_list_tab([_('Flags'), _('Address'), _('Label'), _('Balance'), _('Used')]) l.setContextMenuPolicy(Qt.CustomContextMenu) l.customContextMenuRequested.connect(self.create_receive_menu) self.connect(l, SIGNAL('itemDoubleClicked(QTreeWidgetItem*, int)'), lambda a, b: self.address_label_clicked(a,b,l,1,2)) @@ -754,7 +754,7 @@ class ElectrumWindow(QMainWindow): l.clear() l.setColumnHidden(0,not self.wallet.expert_mode) l.setColumnHidden(3,not self.wallet.expert_mode) - l.setColumnHidden(4,not self.wallet.expert_mode) + #l.setColumnHidden(4,not self.wallet.expert_mode) l.setColumnWidth(0, 50) l.setColumnWidth(1, 310) l.setColumnWidth(2, 250) @@ -775,13 +775,13 @@ class ElectrumWindow(QMainWindow): if not item['is_input'] : n=n+1 if n==0: - tx = "None" + tx = _("never") if address in self.wallet.addresses: gap += 1 if gap > self.wallet.gap_limit: is_red = True else: - tx = "%d"%n + tx = "%d "%n + _('times') if address in self.wallet.addresses: gap = 0 From 0952366a559898cb997ffd406465b39a549c0e69 Mon Sep 17 00:00:00 2001 From: ThomasV Date: Thu, 14 Jun 2012 16:47:13 +0200 Subject: [PATCH 09/34] 'received' is better --- lib/gui_qt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gui_qt.py b/lib/gui_qt.py index c87e71104..1a5b7fe38 100644 --- a/lib/gui_qt.py +++ b/lib/gui_qt.py @@ -658,7 +658,7 @@ class ElectrumWindow(QMainWindow): def create_receive_tab(self): - l,w,hbox = self.create_list_tab([_('Flags'), _('Address'), _('Label'), _('Balance'), _('Used')]) + l,w,hbox = self.create_list_tab([_('Flags'), _('Address'), _('Label'), _('Balance'), _('Received')]) l.setContextMenuPolicy(Qt.CustomContextMenu) l.customContextMenuRequested.connect(self.create_receive_menu) self.connect(l, SIGNAL('itemDoubleClicked(QTreeWidgetItem*, int)'), lambda a, b: self.address_label_clicked(a,b,l,1,2)) From 4e714839753107418a436adc835d4fb2214a9c95 Mon Sep 17 00:00:00 2001 From: ThomasV Date: Thu, 14 Jun 2012 16:53:23 +0200 Subject: [PATCH 10/34] voodoo fix --- lib/gui_qt.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/gui_qt.py b/lib/gui_qt.py index 1a5b7fe38..4239e7e65 100644 --- a/lib/gui_qt.py +++ b/lib/gui_qt.py @@ -210,6 +210,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': + tabs.setCurrentIndex (2) + tabs.setCurrentIndex (3) + tabs.setCurrentIndex (0) + def connect_slots(self, sender): if self.wallet.seed: From 0340b1868a10a79b8181f6d1331837a878c53e9d Mon Sep 17 00:00:00 2001 From: ThomasV Date: Thu, 14 Jun 2012 16:56:20 +0200 Subject: [PATCH 11/34] I guess this should work with seedless wallets --- lib/gui_qt.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/gui_qt.py b/lib/gui_qt.py index 4239e7e65..ecfad22e9 100644 --- a/lib/gui_qt.py +++ b/lib/gui_qt.py @@ -212,8 +212,9 @@ class ElectrumWindow(QMainWindow): # dark magic fix by flatfly; https://bitcointalk.org/index.php?topic=73651.msg959913#msg959913 if platform.system() == 'Windows': - tabs.setCurrentIndex (2) - tabs.setCurrentIndex (3) + n = 2 if self.wallet.seed else 1 + tabs.setCurrentIndex (n) + tabs.setCurrentIndex (n+1) tabs.setCurrentIndex (0) From a3d53c8ab0414c899fe75a669811dd9fe0dbdb2a Mon Sep 17 00:00:00 2001 From: ThomasV Date: Thu, 14 Jun 2012 21:11:37 +0200 Subject: [PATCH 12/34] get_history script --- get_history | 26 ++++++++++++++++++++++++++ watch_address | 1 + 2 files changed, 27 insertions(+) create mode 100755 get_history diff --git a/get_history b/get_history new file mode 100755 index 000000000..32641152e --- /dev/null +++ b/get_history @@ -0,0 +1,26 @@ +#!/usr/bin/env python + +import sys +from electrum import TcpStratumInterface + +try: + addr = sys.argv[1] +except: + print "usage: get_history " + sys.exit(1) + +i = TcpStratumInterface('ecdsa.org', 50001) +i.init_socket() +i.start() +i.send([('blockchain.address.get_history',[addr])]) + +while True: + r = i.responses.get(True, 100000000000) + 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/watch_address b/watch_address index 698d9b487..843ae7449 100755 --- a/watch_address +++ b/watch_address @@ -7,6 +7,7 @@ try: addr = sys.argv[1] except: print "usage: watch_address " + sys.exit(1) i = TcpStratumInterface('ecdsa.org', 50001) i.init_socket() From 1084abeb53e1c28b0cd6b0fd41e9d710cc93b9ab Mon Sep 17 00:00:00 2001 From: ThomasV Date: Fri, 15 Jun 2012 08:28:56 +0200 Subject: [PATCH 13/34] update gui on new block --- lib/interface.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/interface.py b/lib/interface.py index 0e35f6259..3a7bd3db8 100644 --- a/lib/interface.py +++ b/lib/interface.py @@ -363,6 +363,7 @@ class WalletSynchronizer(threading.Thread): elif method == 'blockchain.numblocks.subscribe': self.wallet.blocks = result + self.wallet.was_updated = True elif method == 'server.version': pass From e41966a37bdfc7e3761912f53196c71fff85b88c Mon Sep 17 00:00:00 2001 From: ThomasV Date: Fri, 15 Jun 2012 08:29:52 +0200 Subject: [PATCH 14/34] catch keyboard interrupt --- blocks | 5 ++++- get_history | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/blocks b/blocks index 5491d2c29..2de192e1d 100755 --- 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/get_history b/get_history index 32641152e..50c10a937 100755 --- a/get_history +++ b/get_history @@ -15,7 +15,10 @@ i.start() i.send([('blockchain.address.get_history',[addr])]) while True: - r = i.responses.get(True, 100000000000) + try: + r = i.responses.get(True, 100000000000) + except KeyboardInterrupt: + break method = r.get('method') if method == 'blockchain.address.get_history': confirmed = unconfirmed = 0 From 3d9eb32b50bf55b54d74e52dd86bd106325a802e Mon Sep 17 00:00:00 2001 From: thomasv Date: Fri, 15 Jun 2012 13:46:30 +0200 Subject: [PATCH 15/34] remove unneeded call --- lib/gui_qt.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/gui_qt.py b/lib/gui_qt.py index ecfad22e9..aed7b70ce 100644 --- a/lib/gui_qt.py +++ b/lib/gui_qt.py @@ -212,9 +212,8 @@ class ElectrumWindow(QMainWindow): # dark magic fix by flatfly; https://bitcointalk.org/index.php?topic=73651.msg959913#msg959913 if platform.system() == 'Windows': - n = 2 if self.wallet.seed else 1 + n = 3 if self.wallet.seed else 2 tabs.setCurrentIndex (n) - tabs.setCurrentIndex (n+1) tabs.setCurrentIndex (0) From 717c2de4d4310ddef24953122c060e2d4b8afe17 Mon Sep 17 00:00:00 2001 From: thomasv Date: Fri, 15 Jun 2012 14:01:22 +0200 Subject: [PATCH 16/34] restore headers; needed for unicode --- mki18n.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mki18n.py b/mki18n.py index f6b9409ff..6778be2df 100755 --- 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) From 5cf7570a1a045f7ecfd01670ca7c5550b7b77655 Mon Sep 17 00:00:00 2001 From: ThomasV Date: Sat, 16 Jun 2012 18:24:36 +0200 Subject: [PATCH 17/34] revert to previous; too much clutter --- lib/gui_qt.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/gui_qt.py b/lib/gui_qt.py index aed7b70ce..eb386a815 100644 --- a/lib/gui_qt.py +++ b/lib/gui_qt.py @@ -664,7 +664,7 @@ class ElectrumWindow(QMainWindow): def create_receive_tab(self): - l,w,hbox = self.create_list_tab([_('Flags'), _('Address'), _('Label'), _('Balance'), _('Received')]) + l,w,hbox = self.create_list_tab([_('Flags'), _('Address'), _('Label'), _('Balance'), _('Tx')]) l.setContextMenuPolicy(Qt.CustomContextMenu) l.customContextMenuRequested.connect(self.create_receive_menu) self.connect(l, SIGNAL('itemDoubleClicked(QTreeWidgetItem*, int)'), lambda a, b: self.address_label_clicked(a,b,l,1,2)) @@ -760,7 +760,7 @@ class ElectrumWindow(QMainWindow): l.clear() l.setColumnHidden(0,not self.wallet.expert_mode) l.setColumnHidden(3,not self.wallet.expert_mode) - #l.setColumnHidden(4,not self.wallet.expert_mode) + l.setColumnHidden(4,not self.wallet.expert_mode) l.setColumnWidth(0, 50) l.setColumnWidth(1, 310) l.setColumnWidth(2, 250) @@ -780,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 = _("never") if address in self.wallet.addresses: gap += 1 if gap > self.wallet.gap_limit: is_red = True else: - tx = "%d "%n + _('times') if address in self.wallet.addresses: gap = 0 @@ -843,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) From 4343967ee0061e185cb6f6921a01a8a9c31aaa34 Mon Sep 17 00:00:00 2001 From: ThomasV Date: Sat, 16 Jun 2012 18:45:17 +0200 Subject: [PATCH 18/34] make use_change a stored preference --- lib/gui_qt.py | 39 ++++++++++++++++++--------------------- lib/wallet.py | 12 +++++++++++- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/lib/gui_qt.py b/lib/gui_qt.py index eb386a815..750b6fb08 100644 --- a/lib/gui_qt.py +++ b/lib/gui_qt.py @@ -458,11 +458,6 @@ class ElectrumWindow(QMainWindow): 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\nA suggested fee is automatically added to this field. You may override it. The suggested fee increases with the size of the transaction.')), 4, 3) - self.nochange_cb = QCheckBox(_('Do not create change address')) - grid.addWidget(self.nochange_cb,5,1,1,4) - self.nochange_cb.setChecked(False) - self.nochange_cb.setHidden(not self.wallet.expert_mode) - b = EnterButton(_("Send"), self.do_send) grid.addWidget(b, 6, 1) @@ -562,15 +557,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 @@ -1164,8 +1152,8 @@ class ElectrumWindow(QMainWindow): self.wallet.save() self.update_receive_tab() self.update_contacts_tab() - if self.wallet.seed: - 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): @@ -1199,7 +1187,16 @@ class ElectrumWindow(QMainWindow): 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: + + nochange_cb = QCheckBox(_('Use change addresses')) + grid.addWidget(nochange_cb, 5, 0) + nochange_cb.setChecked(self.wallet.use_change) + 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' \ @@ -1209,14 +1206,11 @@ class ElectrumWindow(QMainWindow): + _('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) @@ -1250,6 +1244,9 @@ class ElectrumWindow(QMainWindow): self.wallet.save() if self.wallet.expert_mode: + + self.wallet.nochange = nochange_cb.isChecked() + try: n = int(gap_e.text()) except: diff --git a/lib/wallet.py b/lib/wallet.py index 5517fd5a6..c1769b02d 100644 --- 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, @@ -653,6 +655,7 @@ class Wallet: 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') @@ -878,12 +881,19 @@ class Wallet: tx['default_label'] = default_label - def mktx(self, to_address, amount, label, password, fee=None, change_addr=None, from_addr= None): + def mktx(self, to_address, amount, label, password, fee=None, from_addr= None): if not self.is_valid(to_address): raise BaseException("Invalid address") inputs, total, fee = self.choose_tx_inputs( amount, fee, from_addr ) if not inputs: raise BaseException("Not enough funds") + + if self.use_change: + change_addr = inputs[0][0] + print "sending change to", change_addr + else: + change_addr = None + outputs = self.choose_tx_outputs( to_address, amount, fee, total, change_addr ) s_inputs = self.sign_inputs( inputs, outputs, password ) From 81ab47a984c53cee2e9d16706f1ec3c88ee93c60 Mon Sep 17 00:00:00 2001 From: ThomasV Date: Sat, 16 Jun 2012 18:56:55 +0200 Subject: [PATCH 19/34] fix: nochange -> usechange --- lib/gui_qt.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/gui_qt.py b/lib/gui_qt.py index 750b6fb08..a94c4574e 100644 --- a/lib/gui_qt.py +++ b/lib/gui_qt.py @@ -1193,9 +1193,10 @@ class ElectrumWindow(QMainWindow): if self.wallet.expert_mode: - nochange_cb = QCheckBox(_('Use change addresses')) - grid.addWidget(nochange_cb, 5, 0) - nochange_cb.setChecked(self.wallet.use_change) + 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' \ @@ -1245,7 +1246,7 @@ class ElectrumWindow(QMainWindow): if self.wallet.expert_mode: - self.wallet.nochange = nochange_cb.isChecked() + self.wallet.use_change = usechange_cb.isChecked() try: n = int(gap_e.text()) From ea07c26ad97687b9ba82f17625df7179a268cc5c Mon Sep 17 00:00:00 2001 From: ThomasV Date: Sat, 16 Jun 2012 19:40:31 +0200 Subject: [PATCH 20/34] version --- lib/version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/version.py b/lib/version.py index 4cc90f4a5..49f41e169 100644 --- a/lib/version.py +++ b/lib/version.py @@ -1,3 +1,3 @@ -ELECTRUM_VERSION = "0.58" +ELECTRUM_VERSION = "0.59" SEED_VERSION = 4 # bump this everytime the seed generation is modified -TRANSLATION_ID = 27601 # version of the wiki page +TRANSLATION_ID = 27842 # version of the wiki page From c6c577dcfdbed19cef55177e24fc358c682fc0af Mon Sep 17 00:00:00 2001 From: ThomasV Date: Sun, 17 Jun 2012 06:58:36 +0200 Subject: [PATCH 21/34] fix: confusion --- lib/wallet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/wallet.py b/lib/wallet.py index c1769b02d..2725d5229 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -888,7 +888,7 @@ class Wallet: if not inputs: raise BaseException("Not enough funds") - if self.use_change: + if not self.use_change: change_addr = inputs[0][0] print "sending change to", change_addr else: From 3801956bee9785dc452b86b849c0b9e6545fc999 Mon Sep 17 00:00:00 2001 From: ThomasV Date: Sun, 17 Jun 2012 06:59:12 +0200 Subject: [PATCH 22/34] version 0.59a --- lib/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/version.py b/lib/version.py index 49f41e169..7e5217e96 100644 --- a/lib/version.py +++ b/lib/version.py @@ -1,3 +1,3 @@ -ELECTRUM_VERSION = "0.59" +ELECTRUM_VERSION = "0.59a" SEED_VERSION = 4 # bump this everytime the seed generation is modified TRANSLATION_ID = 27842 # version of the wiki page From 37af22cc6f4b4e7c6d8ea51b8a9980d51b8c25b7 Mon Sep 17 00:00:00 2001 From: ThomasV Date: Sun, 17 Jun 2012 09:51:15 +0200 Subject: [PATCH 23/34] fix for change address --- lib/version.py | 2 +- lib/wallet.py | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/version.py b/lib/version.py index 7e5217e96..92fac76fd 100644 --- a/lib/version.py +++ b/lib/version.py @@ -1,3 +1,3 @@ -ELECTRUM_VERSION = "0.59a" +ELECTRUM_VERSION = "0.59b" SEED_VERSION = 4 # bump this everytime the seed generation is modified TRANSLATION_ID = 27842 # version of the wiki page diff --git a/lib/wallet.py b/lib/wallet.py index 2725d5229..2df1e743a 100644 --- a/lib/wallet.py +++ b/lib/wallet.py @@ -881,18 +881,16 @@ class Wallet: tx['default_label'] = default_label - def mktx(self, to_address, amount, label, password, fee=None, from_addr= None): + def mktx(self, to_address, amount, label, password, fee=None, change_addr=None, from_addr= None): if not self.is_valid(to_address): raise BaseException("Invalid address") inputs, total, fee = self.choose_tx_inputs( amount, fee, from_addr ) if not inputs: raise BaseException("Not enough funds") - if not self.use_change: + if not self.use_change and not change_addr: change_addr = inputs[0][0] print "sending change to", change_addr - else: - change_addr = None outputs = self.choose_tx_outputs( to_address, amount, fee, total, change_addr ) s_inputs = self.sign_inputs( inputs, outputs, password ) From d3c7781803eec057cd62da5aa9575f743b9292b4 Mon Sep 17 00:00:00 2001 From: Maran Date: Mon, 18 Jun 2012 22:19:47 +0200 Subject: [PATCH 24/34] Added some more information for certain help commands also rewrote some of them to be more like the others --- electrum | 57 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/electrum b/electrum index 14f93fc11..7886de496 100755 --- 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 [
]", + 'help':'Prints this help', + 'validateaddress':'Check that the address is valid', + 'balance': "Display the balance of your wallet or of an address.\nSyntax: balance [
]", 'contacts': "Show your list of contacts", - 'create':'create wallet', - 'restore':'restore wallet', - 'payto':""" - payto [label] - create and broadcast a transaction. - 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 [label] + 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 - broadcast a transaction to the network. must be in hexadecimal""", + 'Broadcasts a transaction to the network. \nSyntax: sendtx \n 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