Skip to content
Snippets Groups Projects
Commit 36e1dcae authored by Vincent Texier's avatar Vincent Texier
Browse files

[feat] #150 Add DUBP Mnemonic SigningKey feature

parent 5aad2059
No related branches found
No related tags found
1 merge request!125Mnemonic dewif
......@@ -17,12 +17,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import base64
import re
import struct
from os import PathLike
from typing import Optional, Union, TypeVar, Type
import libnacl.sign
import pyaes
from libnacl.utils import load_key
from hashlib import scrypt
from hashlib import scrypt, sha256
from pyaes import AESModeOfOperationECB
from .scrypt_params import ScryptParams
from .base58 import Base58Encoder
......@@ -31,8 +35,25 @@ from ..tools import (
xor_bytes,
convert_seedhex_to_seed,
convert_seed_to_seedhex,
dubp_mnemonic_to_seed,
)
DEWIF_CURRENCY_CODE_NONE = 0x00000000
DEWIF_CURRENCY_CODE_G1 = 0x00000001
DEWIF_CURRENCY_CODE_G1_TEST = 0x10000001
def chunkstring(data: bytes, length: int):
"""
Return a tuple of chunks sized at length from the data bytes
:param data: Data to split
:param length: Size of chunks
:return:
"""
return (data[0 + i : length + i] for i in range(0, len(data), length))
# required to type hint cls in classmethod
SigningKeyType = TypeVar("SigningKeyType", bound="SigningKey")
......@@ -509,3 +530,13 @@ Data: {data}""".format(
seed = bytes(base64.b64decode(secret)[0:32])
return cls(seed)
@classmethod
def from_dubp_mnemonic(cls, mnemonic: str):
"""
Generate key pair instance from a DUBP mnemonic passphrase (128 bits, twelve words)
:param mnemonic: DUBP mnemonic passphrase
:return:
"""
return cls(dubp_mnemonic_to_seed(mnemonic))
......@@ -16,9 +16,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import uuid
from hashlib import sha256, scrypt
from typing import Union
from libnacl.encode import hex_decode, hex_encode
from duniterpy.key.scrypt_params import ScryptParams
def ensure_bytes(data: Union[str, bytes]) -> bytes:
"""
......@@ -87,3 +90,18 @@ def get_ws2p_challenge() -> str:
:rtype str:
"""
return str(uuid.uuid4()) + str(uuid.uuid4())
def dubp_mnemonic_to_seed(mnemonic: str) -> bytes:
"""
Return a seed from a 128 bits mnemonic (twelve words)
:param mnemonic: 128 bits mnemonic
:return:
"""
password = mnemonic.encode("utf-8") # type: bytes
salt = sha256(b"dubp" + password).digest() # type: bytes
seed = scrypt(
password=password, salt=salt, n=4096, r=16, p=1, dklen=32
) # type: bytes
return seed
......@@ -14,7 +14,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import base64
import os
from duniterpy.key import VerifyingKey, SigningKey, PublicKey
......@@ -144,3 +144,16 @@ class TestSigningKey(unittest.TestCase):
sign_key_load.vk.hex(),
"d27f4cb2bfadbaf45b61714b896d4639ab90db035aee746611cdd342bdaa8996",
)
def test_dubp_mnemonic(self):
mnemonic = (
"tongue cute mail fossil great frozen same social weasel impact brush kind"
)
keypair = SigningKey.from_dubp_mnemonic(mnemonic)
self.assertEqual(
base64.b64encode(keypair.seed).decode("utf-8"),
"qGdvpbP9lJe7ZG4ZUSyu33KFeAEs/KkshAp9gEI4ReY=",
)
self.assertEqual(keypair.pubkey, "732SSfuwjB7jkt9th1zerGhphs6nknaCBCTozxUcPWPU")
import base64
import unittest
from duniterpy import tools
class TestTools(unittest.TestCase):
def test_dubp_mnemonic_to_seed(self):
"""
https://git.duniter.org/documents/rfcs/blob/dubp-mnemonic/rfc/0014_Dubp_Mnemonic.md
:return:
"""
mnemonic = (
"tongue cute mail fossil great frozen same social weasel impact brush kind"
)
seed = tools.dubp_mnemonic_to_seed(mnemonic)
self.assertEqual(
"qGdvpbP9lJe7ZG4ZUSyu33KFeAEs/KkshAp9gEI4ReY=",
base64.b64encode(seed).decode("utf-8"),
)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment