پیشنیاز
توابع هش
آدرس کیفپول، کلید عمومی و خصوصی
دیدین بعضی از کیفپولهای ارزهای دیجیتال چندتا کلمه بهتون میدن بعد از همون چندتا کلمه براتون کلی حساب بیتکوین و هزارتا ارز دیجیتال دیگه باز میکنن؟
آخه چجوری؟ این اصلا امن هست؟
+ معمولا شما یه کلید خصوصی و یه کلید عمومی دارین برای هر کوین، مثلا بیتکوین، و هی از اون آدرس مقداری بیتکوین به آدرسهای دیگه میفرستین یا دریافت میکنید. درسته؟ نه دیگه، درست نیست، زخم میشه اون آدرس، و اصلا رویکرد امنی هم نیست.
- خب پس چیکار باید کرد؟
+ باید از آدرسهای مختلف استفاده کنید، هربار از یه آدرس برای ارسال بیتکوین استفاده کنید، و همین رویکرد را باید نسبت به کوینهای دیگه داشت.
- آخه این چه راهکاریه؟ یعنی من هردفعه بیتکوینمیخوام دریافت کنم اونها را بریزم تو یه آدرس منحصر؟ اونوقت اینجوری که صدها و هزارها آدرس خواهم داشت، چطور مدیریت کنم آخه؟ بعد اگه همه بخوان اینکار را انجام بدن که آدرسهای موجود بیتکوین همه استفاده میشن، چیزی برای بقیه نمیمونه!!!
+ سوال اولت خوب بود اما مردهشور سوال دومت را ببرن ?♂?♂?♂
جواب سوال اولت اینه که راه حل استفاده از کیفپولهای HD هست.
کیفپول (Hierarchical Deterministic (HD
وقتی شما از کیفپول HD استفاده میکنید به شما فقط یک مجموعه از کلمات داده میشود (از الان بهشون seed phrase و یا master seed میگیم) که با استفاده از ریاضیات و الگوریتم میشه از دل اون صدها (در تئوری، بینهایت) آدرس مختلف برای هر ارز دیجیتال استخراج کرد. این آدرسها دارای ساختار درختی هستند، یعنی شما یه آدرس دارید که اون آدرس خودش میتونه بینهایت آدرس خواهر و برادر داشته باشه (آدرسهای برادر همانند حسابهای مختلف بانکی میباشند که برای اهداف متفاوت افتتاح شدند)، و همچنین بینهایت آدرس فرزند داشته باشه (آدرسهای فرزند همانند صفحات چک از میان یک دسته چک میباشند که همگی متعلق به یه حساب بانکی هستند اما برای عملیات مختلف بانکی استفاده میشوند).
بنابراین شما دیگه نیاز ندارید همه آدرسهاتون را حفظ کنید یا مدیریت کنید، فقط باید seed phrase را حفظ کنید یا به نحو مطمئن در جایی نگهداری کنید.
به این ترتیب، اگه کیفپول سختافزاری یا کامپیوتر شما خراب بشه یا گم بشه شما فقط به seed phrase تون برای بازیابی کیفپول و ارزهای خود نیاز خواهید داشت.
- عااامووو مگه میشه؟ آخه چطوووری؟
+ الان توضیح میدم
فرایند تولید Master Seed
از استاندارد BIP39 برای تولید master seed استفاده میشه.
اینجا من رو استفاده از استاندارد BIP39 جهت تولید pass phrase بیست و چهار کلمهای متمرکز میشم ولی فرایند تولید این مجموعه کلمات برای حالات دیگه مثل حالت دوازده کلمهای تقریبا یکسان هست.
این بیست و چهار کلمه بصورت تصادفی از یه لغتنامه ۲۰۴۸ کلمهای استخراج میشن.
فرایند تصادفی استخراج این بیستوچهار کلمه بصورت زیر است:
۱- در قدم اول یه رشته از ۲۵۶ بیت بصورت تصادفی تولید میشه. چگونگی این فرایند تصادفی خودش داستانها داره. یک روش ابتدایی اینه که مثلا شما یه عکس شخصی دارین که تا حالا با کسی به اشتراک نذاشتید و هرگز رو اینترنت آپلود نکردید. این عکس در حقیقت یک رشته بیت ذخیرهشده هست. شما این رشته بیت را میدین به یه تابع هش و به عنوان خروجی ۲۵۶ بیت دریافت میکنید. البته از روشهای پیچیدهتر برای تولید این ۲۵۶ بیت تصادفی استفاده میشه و خود کیفپول شما این فرایند را مدیریت میکنه بنابراین شما نیازی به دانش تخصصی نخواهید داشت.
۲- این ۲۵۶ بیت تصادفی طی یه فرایند تبدیل به یه رشته ۲۶۴ بیتی میشود. این فرایند به شکل زیر است:
این ۲۵۶ بیت تصادفی به تابع هش SHA-256 داده میشه و ۲۵۶ بیت جدید به عنوان خروجی دریافت میشه، سپس هشت بیت اول این ۲۵۶ بیت جدید به آخر اون ۲۵۶ بیت تصادفی اولیه اضافه میشه. پس الان ما یه رشته جدید ۲۶۴ بیتی خواهیم داشت.
۳- در قدم بعد، رشته ۲۶۴ بیتی ما به ۲۴ گروه ۱۱ بیتی تقسیم میشه
۴- هر گروه ۱۱ بیتی به یه عدد دهدهی بین ۰ تا ۲۰۴۷ تبدیل میشه، سپس به لغتنامه ۲۰۴۸ کلمهای که قبلا بهش اشاره کردم رجوع میشه و کلمه متناظر با این عدد در اون لغتنامه پیدا میشه.
در پایان این فرایند ما ۲۴ کلمه خواهیم داشت.
- داداش هنر کردی، این همه تفت دادی که ۲۴ تا کلمه پیدا کنی؟ خب اینرا که خودم میرفتم از تو دیکشنری پیدا میکردم. کلید خصوصی و عمومی را چطور تولید میکنی؟
+ الان توضیح میدم. اما قبل از اون یه نکته:
در این مرحله شما باید این ۲۴ کلمه را یا تو مغزتون یا جای مطمئن دیگه ذخیره کنید. مراحل بعدی توسط کیفپول شما مدیریت میشه.
پس تو این فرایند شما فقط قراره یه کار کنید و اون ذخیره کردن این ۲۴ کلمه بصورت امن هست. تکرار میکنم، فقط یه کار! تو رو خدا درست انجام بدینش.
فرایند تولید ریشه یا master node
بعد از تولید تصادفی این ۲۴ کلمه، اونها باید دوباره تبدیل به یه رشته باینری بشن. برای این فرایند از تابع هش PBKDF2-HMAC-SHA512 استفاده میشه، اون ۲۴ کلمه وارد تابع میشن و یه رشته ۵۱۲ بیتی از تابع خارج میشه. این رشته ۵۱۲ بیتی ریشه کیف پول شما (که ساختار یه درخت داره) محسوب میشه. هر کلید خصوصی و عمومی تولید شده در کیف پول شما از این ۵۱۲ بیت ریشه میگیره.
قدم بعدی تولید کلیدهای خصوصی و عمومی از این ریشه باینری هست. اما قبلش نیاز دارم مفهوم path level را توضیح بدم.
تعریف path level در کیفپول
برای تولید هر زوج کلید خصوصی و عمومی برای هر ارز دیجیتال باید اول یه عبارت منحصربفرد به اون کلید و آدرس اختصاص داد تا بشه اون را از آدرسهای دیگه متمایز کرد. مثلا شما میتونید عبارت
کیف پول بیتکوین شماره یک برای ذخیره و نگهداری بیتکوینهای عزیزم، باشد که روزی رستگار شوم
را به یکی از آدرس های خود اختصاص دهید. (اینجا داریم صرفا آدرس های مختلف خود را نامگذاری می کنیم)
اما این روش که شما اتخاذ کردید خیلی بیقاعده هست، بگذارید یه روش سیستماتیک و مورد پسند و تایید همه ابداع کنیم:
به این منظور ما از path levels استفاده میکنیم. فرمت یه path level به شکل زیر است:
m / purpose' / coin_type' / account' / change / address_index
تو این مقاله من اون آپستروف های تو path level را بیخیال میشم. اما بقیه اجزای path level اینجور تعریف میشن:
m/
فقط یه روش برای اینه که بگیم این عبارت یه متن هست (و نه یه کد).
purpose
این جز از path level یه عدد ثابت هست، که تو مورد کیفپول ما برابر با 44' یا (0x8000002C) هست و بیانگر این هست که شاخههای این درخت با پیروی از استاندارد BIP43 استخراج شدهاند.
coin_type
همونطور که قبلا گفتم شما میتونید از یه (master node (seed برای تولید آدرس برای ارزهای مختلف مثل بیتکوین، لایتکوین، اتریوم ... استفاده کنید.
این متغیر تو path level مشخص میکنه که شما این آدرس را برای چه ارز دیجیتال میخواهید استفاده کنید. طی یه اجماع، به هر رمزارز یه عدد ثابت اختصاص داده شده و اون عدد ثابت را در قسمت coin_type وارد میکنند تا بگن قصد تولید آدرس و کلید برای کدام رمزارز را دارن.
account
در این قسمت شما میتونید حسابهای مختلف برای هر رمزارز، مثلا بیتکوین، ایجاد کنید. مثلا یه آدرس اختصاص بدین به حساب پسانداز بیتکوین و اون را با عدد صفر متمایز کنید، سپس یه آدرس اختصاص بدین به حساب متصل به صرافیها و اون را با عدد یک متمایز کنید، یه آدرس اختصاص بدین به امور خیریهتون و اون را با عدد دو متمایز کنید ...
همان طور که ملاحظه شد به این حسابهای متفاوت یه عدد اختصاص داده میشود که از صفر شروع میشود و تا بینهایت میتواند ادامه داشته باشد. این عددها یا نمایه بیانگر آدرسهای خواهر و برادر در ساختار درختی ما میباشند.
change
در این قسمت، عدد ۰ به external chain و عدد ۱ به internal chain (آدرس های مرتبط با change address) نسبت داده میشود. در واقع، external chain شامل آدرس هایی میشود که خارج از کیفپول هم قابل مشاهده هستند و شما میتوانید به منظور دریافت بیتکوین آنها را به اشتراک بگذارید. از طرف دیگر internal chain شامل آدرسهایی هست که قرار نیست خارج از کیفپول قابل مشاهده باشن و برای مدیریت خرده بیتکوینهای باقیمانده از مبادلات استفاده میشن.
index
مقدار این متغیر از صفر شروع میشه و میتونه تا بینهایت افزایش پیدا کنه و در حقیقت یه نمایه برای آدرسها و کلیدهای فرزند میباشد.
مثال:
فرض کنید من میخوام یه حساب اتر برای اترهای خودم باز کنم و یه حساب اتر دیگه برای اترهای شرکتی که براش کار میکنم. با اینکار میخوام سرمایه شخصی خودم را از سرمایه شرکت جدا کنم.
در این حالت من از path level یا همون عبارت منحصربفرد متمایز کننده زیر برای حساب شخصی
m/44'/60'/0'/0'/0
و از path level زیر برای حساب شرکت استفاده میکنم:
m/44'/60'/1'/0'/0
اینجا عدد ۶۰ یه عدد از پیش اختصاص داده شده و مورد اجماع قرار گرفته برای ارز اتریوم هست.
در path level اول بعد از عدد ۶۰ از نمایه ۰ استفاده شده که متناظر با حساب شخصی من هست و در path level دوم بعد از عدد ۶۰ از نمایهی ۱ استفاده شده که متناظر با حساب شرکتی من خواهد بود.
حال فرض کنید برای حساب شرکت به جای یک حساب واحد من میخواهم سه زیرحساب یا سه حساب فرزند باز کنم. یکی برای امور جاری و کوتاهمدت شرکت، یکی برای سرمایهگذاری و امور بلند مدت شرکت، و آخری برای پرداخت حقوق کارمندان.
در این حالت من از سه تا path level جدید برای نشون دادن این دو حساب فرزند استفاده میکنم:
m/44'/60'/1'/0'/0
برای حساب شرکتی مختص به امور کوتاه مدت شرکت و
m/44'/60'/1'/0'/1
برای حساب شرکتی مختص به سرمایهگذاری و امور بلند مدت، و همچنین
m/44'/60'/1'/0'/2
برای حساب شرکتی مختص به پرداخت حقوق و مطالبات.
به این ترتیب ما یک سیستم نامگذاری جهانشمول و محمدیپسند برای نامگذاری حسابهای مختلف خود ایجاد کردیم.
ولی کامپیوتر که این نامگذاری ها و عددهای مقیاس دهدهی سرش نمیشه، بنابراین در مرحله بعد همه اینها تبدیل به یک رشته بیت میشن.
تا به اینجا ما دو تا داده مهم داریم، یکی master node هست که یه رشته ۵۱۲ بیتی هست و دیگری path level که نهایتا خودش یه رشته بیت خواهد بود. این رشته بیتها به فرمت زیر در کنار هم قرار میگیرند:
Master node / Purpose Code / Coin Code / Account Index / Change Address / Child Index
این رشته بیت سپس وارد یه تابع هش میشه و یه رشته بیت ۵۱۲ بیتی به عنوان خروجی ارائه میدهد. ۲۵۶ بیت نخست که در چپ این رشته بیت خروجی قرار دارد همان کلید خصوصی شما خواهد بود و ۲۵۶ بیت پایانی که در سمت راست قرار دارد chain code نامیده میشود. در این مقاله به chain node نمیپردازم اما اجمالا بگم که علت وجودی آن این است که اگر به هر دلیلی کسی به کلید خصوصی و عمومی یکی از حسابهای شما دست پیدا کرد به علت وجود chain node هنوز برای او غیر ممکن خواهد بود که به کلید خصوصی حسابهای فرزند دست پیدا کند.
از اینجا به بعد فرایند ساخت آدرس ها و کلید های جدید تکراری میباشد. یعنی اگر میخواهید یک آدرس برادر یا فرزند بسازید باید رشته بیت زیر را
Public key of parent node / Chain Code of parent node / Purpose Code / Coin Code / Account Index (Index of brother account) / Change Address / Child Index
را به تابع هش بدهید و یه خروجی ۵۱۲ بیتی دریافت کنید، ۲۵۶ بیت نخست کلید خصوصی و ۲۵۶ بیت پایانی chain code خواهد بود.
منابع
https://ledger.readthedocs.io/en/latest/index.html
https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
http://aaronjaramillo.org/bip-44-hierarchical-deterministic-wallets