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

[feat] #150 Add DUBP Mnemonic SigningKey feature

See the RFC0014 of the Duniter Project
parent 5aad2059
No related branches found
No related tags found
No related merge requests found
...@@ -17,12 +17,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. ...@@ -17,12 +17,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import base64 import base64
import re import re
import struct
from os import PathLike
from typing import Optional, Union, TypeVar, Type from typing import Optional, Union, TypeVar, Type
import libnacl.sign import libnacl.sign
import pyaes import pyaes
from libnacl.utils import load_key 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 .scrypt_params import ScryptParams
from .base58 import Base58Encoder from .base58 import Base58Encoder
...@@ -33,6 +37,22 @@ from ..tools import ( ...@@ -33,6 +37,22 @@ from ..tools import (
convert_seed_to_seedhex, convert_seed_to_seedhex,
) )
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 # required to type hint cls in classmethod
SigningKeyType = TypeVar("SigningKeyType", bound="SigningKey") SigningKeyType = TypeVar("SigningKeyType", bound="SigningKey")
...@@ -509,3 +529,27 @@ Data: {data}""".format( ...@@ -509,3 +529,27 @@ Data: {data}""".format(
seed = bytes(base64.b64decode(secret)[0:32]) seed = bytes(base64.b64decode(secret)[0:32])
return cls(seed) return cls(seed)
@classmethod
def from_dubp_mnemonic(cls, mnemonic: str, scrypt_params: ScryptParams = None):
"""
Generate key pair instance from a DUBP mnemonic passphrase
:param mnemonic: Passphrase generated from a mnemonic algorithm
:param scrypt_params: ScryptParams instance (default=None)
:return:
"""
if scrypt_params is None:
scrypt_params = ScryptParams()
_password = mnemonic.encode("utf-8") # type: bytes
_salt = sha256(b"dubp" + _password).digest() # type: bytes
_seed = scrypt(
password=_password,
salt=_salt,
n=scrypt_params.N, # 4096
r=scrypt_params.r, # 16
p=scrypt_params.p, # 1
dklen=scrypt_params.seed_length, # 32
) # type: bytes
return cls(_seed)
...@@ -14,7 +14,7 @@ GNU General Public License for more details. ...@@ -14,7 +14,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
import base64
import os import os
from duniterpy.key import VerifyingKey, SigningKey, PublicKey from duniterpy.key import VerifyingKey, SigningKey, PublicKey
...@@ -144,3 +144,16 @@ class TestSigningKey(unittest.TestCase): ...@@ -144,3 +144,16 @@ class TestSigningKey(unittest.TestCase):
sign_key_load.vk.hex(), sign_key_load.vk.hex(),
"d27f4cb2bfadbaf45b61714b896d4639ab90db035aee746611cdd342bdaa8996", "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")
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment