Skip to content
This repository was archived by the owner on Jan 13, 2023. It is now read-only.

Commit a6ecf24

Browse files
committed
[#61] Fix incorrect keys when seed is longer than 81 trytes.
1 parent 094b53e commit a6ecf24

File tree

3 files changed

+59
-17
lines changed

3 files changed

+59
-17
lines changed

iota/crypto/kerl/pykerl.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from sha3 import keccak_384
66
from six import PY2
7+
from typing import MutableSequence, Optional
78

89
from iota.crypto.kerl import conv
910
from iota.exceptions import with_context
@@ -16,12 +17,29 @@
1617
TRIT_HASH_LENGTH = 243
1718

1819
class Kerl(object):
20+
k = None # type: keccak_384
21+
1922
def __init__(self):
2023
self.reset()
2124

2225
def absorb(self, trits, offset=0, length=None):
26+
# type: (MutableSequence[int], int, Optional[int]) -> None
27+
"""
28+
Absorb trits into the sponge from a buffer.
29+
30+
:param trits:
31+
Buffer that contains the trits to absorb.
32+
33+
:param offset:
34+
Starting offset in ``trits``.
35+
36+
:param length:
37+
Number of trits to absorb. Defaults to ``len(trits)``.
38+
"""
2339
# Pad input if necessary, so that it can be divided evenly into
2440
# hashes.
41+
# Note that this operation creates a COPY of ``trits``; the
42+
# incoming buffer is not modified!
2543
pad = ((len(trits) % TRIT_HASH_LENGTH) or TRIT_HASH_LENGTH)
2644
trits += [0] * (TRIT_HASH_LENGTH - pad)
2745

@@ -57,6 +75,24 @@ def absorb(self, trits, offset=0, length=None):
5775
offset += TRIT_HASH_LENGTH
5876

5977
def squeeze(self, trits, offset=0, length=None):
78+
# type: (MutableSequence[int], int, Optional[int]) -> None
79+
"""
80+
Squeeze trits from the sponge into a buffer.
81+
82+
:param trits:
83+
Buffer that will hold the squeezed trits.
84+
85+
IMPORTANT: If ``trits`` is too small, it will be extended!
86+
87+
:param offset:
88+
Starting offset in ``trits``.
89+
90+
:param length:
91+
Number of trits to squeeze from the sponge.
92+
93+
If not specified, defaults to :py:data:`TRIT_HASH_LENGTH` (i.e.,
94+
by default, we will try to squeeze exactly 1 hash).
95+
"""
6096
# Pad input if necessary, so that it can be divided evenly into
6197
# hashes.
6298
pad = ((len(trits) % TRIT_HASH_LENGTH) or TRIT_HASH_LENGTH)
@@ -89,8 +125,8 @@ def squeeze(self, trits, offset=0, length=None):
89125
trits_from_hash = conv.convertToTrits(signed_hash)
90126
trits_from_hash[TRIT_HASH_LENGTH - 1] = 0
91127

92-
stop = min(TRIT_HASH_LENGTH, length)
93-
trits[offset:stop] = trits_from_hash[0:stop]
128+
stop = min(TRIT_HASH_LENGTH, length-offset)
129+
trits[offset:offset+stop] = trits_from_hash[0:stop]
94130

95131
flipped_bytes = bytearray(conv.convert_sign(~b) for b in unsigned_hash)
96132

iota/crypto/signing.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -240,10 +240,10 @@ def __init__(self, seed, start, step, security_level):
240240

241241
# In order to work correctly, the seed must be padded so that it is
242242
# a multiple of 81 trytes.
243-
pad = (len(seed) % Hash.LEN) or Hash.LEN
244-
self.seed = seed + b'9' * (Hash.LEN - pad)
243+
seed += b'9' * (Hash.LEN - ((len(seed) % Hash.LEN) or Hash.LEN))
245244

246245
self.security_level = security_level
246+
self.seed_as_trits = seed.as_trits()
247247
self.start = start
248248
self.step = step
249249

@@ -262,7 +262,7 @@ def __next__(self):
262262
sponge = self._create_sponge(self.current)
263263

264264
key = [0] * (self.fragment_length * self.security_level)
265-
buffer = [0] * HASH_LENGTH # type: MutableSequence[int]
265+
buffer = [0] * len(self.seed_as_trits)
266266

267267
for fragment_seq in range(self.security_level):
268268
# Squeeze trits from the buffer and append them to the key, one
@@ -275,7 +275,10 @@ def __next__(self):
275275

276276
key_stop = key_start + HASH_LENGTH
277277

278-
key[key_start:key_stop] = buffer
278+
# Ensure we only capture one hash from the buffer, in case
279+
# it is longer than that (i.e., if the seed is longer than 81
280+
# trytes).
281+
key[key_start:key_stop] = buffer[0:HASH_LENGTH]
279282

280283
private_key =\
281284
PrivateKey.from_trits(
@@ -302,7 +305,7 @@ def _create_sponge(self, index):
302305
"""
303306
Prepares the hash sponge for the generator.
304307
"""
305-
seed = self.seed.as_trits() # type: MutableSequence[int]
308+
seed = self.seed_as_trits[:]
306309

307310
for i in range(index):
308311
# Treat ``seed`` like a really big number and add ``index``.

test/crypto/signing_test.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,23 @@
1212
# noinspection SpellCheckingInspection
1313
class KeyGeneratorTestCase(TestCase):
1414
"""
15-
Unit tests for KeyGenerator.
15+
Generating validation data using the JS lib:
1616
17-
Strap in, folks; SigningKeys are multiples of 2187 trytes long!
17+
.. code-block:: javascript
1818
19-
Note to developers: to pretty-format signing keys so that this file
20-
doesn't exceed 80 chars per line, run the byte string through this
21-
code and then copy-paste the result into your test:
19+
// Specify parameters used to generate the private key.
20+
var seed = 'SEED9GOES9HERE';
21+
var keyIndex = 42;
22+
var securityLevel = 3;
2223
23-
.. code-block:: python
24+
var Converter = require('./lib/crypto/converter/converter');
25+
var Signing = require('./lib/crypto/signing/signing');
2426
25-
print('\n'.join(repr(s[i:i+66]) for i in range(0, len(s), 66)))
27+
// Generate the key.
28+
var privateKey = Signing.key(Converter.trits(seed), keyIndex, securityLevel);
2629
27-
References:
28-
- http://stackoverflow.com/a/1751478/
30+
// Output human-readable version.
31+
console.log(Converter.trytes(privateKey));
2932
"""
3033
def test_get_keys_single(self):
3134
"""
@@ -188,7 +191,7 @@ def test_get_keys_long_seed(self):
188191
b'IGVTKTOFGZAIMWHNQWWENEFBAYZXBYWK9QBIWKTMO9MFZIEQVJULQILER9GRDCBLEY'
189192
b'OPLCYJALVJESQMIEZOVOPYYAOLJMIUCGAJLIUFKHTIHZSEOYYLTPHKSURQSWPQEESV'
190193
b'99QM9DUSKSMLSCCDYMDAJIAPGJIHWBROISBLAA9GZFGPPRPHSTVNJMPUWGLTZEZEGQ'
191-
b'HIHMCRZILISRFGVOJMXOYRALR9ZOUAMQXGW9XPFID'
194+
b'HIHMCRZILISRFGVOJMXOYRALR9ZOUAMQXGW9XPFID',
192195
)
193196

194197
self.assertListEqual(

0 commit comments

Comments
 (0)