امضای دیجیتال : معرفی امضای BLS
تراکنشهایی که قرار است در بلاکها ثبت و ذخیره شوند باید به دست کاربران شبکه امضا شوند. از انواع امضاهای معروف و قدیمی میتوانیم به امضای ECDSA و امضای اشنور (Schnorr) اشاره کنیم. اما امضای دیگری تحت عنوان BLS وجود دارد که مشکلات امضاهای قبلی را برطرف کرده است. در این مطلب میخواهیم ببینیم سازوکار امضای BLS چگونه است و چه ویژگیهایی دارد.
پیش از این درباره امضای اشنور (Schnorr) برای شما نوشتیم و گفتیم که چرا این امضا تا این اندازه فوق العاده است. اکنون در این پست میخواهیم به امضای Boneh-Lynn-Shacham یا امضای BLS بپردازیم و بگوییم این امضا چه ویژگیهای بینظیری دارد که امضای اشنور فاقد آن است.
به طور خلاصه، آنچه تاکنون میدانیم به شرح زیر است:
امضاهای ECDSA (یا الگوریتم امضای دیجیتال منحنی بیضوی) خوبند و کار خود را به درستی انجام میدهند، اما از این فراتر نمیروند. شما نمیتوانید این امضاها یا کلیدها را با هم ترکیب کنید و هر امضا باید به طور مستقل تایید شود. این قضیه با توجه به تراکنشهای چندامضایی بیاندازه آزاردهنده میشود. چون باید همهی امضاها و کلیدهای عمومی متناظر آن را یک به یک بررسی کنید، فضای بسیار زیادی را در داخل بلاکها هدر بدهید و هزینهی زیادی بپردازید.
امضاهای اشنور فوق العادهاند. اگر قدمهای لازمه را درست برداریم میتوانیم تمام امضاها و کلیدهای عمومی تراکنش را درون یک کلید منفرد و یک امضا ترکیب کنیم تا هیچکس نفهمد که آن کلید و امضا مربوط به کدام کلیدهاست. علاوه بر این، فرآیند تایید بلاکها هم میتواند با سرعت بیشتری انجام شود، چون میتوانیم تمام امضاها را در یک لحظه اعتبارسنجی کنیم. با این حال، امضاهای اشنور چند مشکل دارند:
- روش چندامضایی نیازمند چند دور ارتباط و تعامل است. این مسئله بهخصوص با توجه به فضای ذخیرهسازی سرد میتواند خیلی آزاردهنده شود.
- با توجه به تراکم امضاها باید بر مولد عدد تصادفی تکیه کنیم، چون دیگر نمیتوانیم مثل کاری که در ECDSA انجام میدهیم، نقطهی تصادفیِ R را انتخاب نماییم.
- روش چندامضایی m از n مستعد ریسک است. باید درخت مرکلی از کلیدهای عمومی بسازیم که قابلیت گسترش یافتن برای m و n را داشته باشد.
- نمیتوانیم تمام امضاهای بلاک را درون یک امضای منفرد ترکیب کنیم.
امضاهای BLS میتوانند تمام مشکلات بالا را حل کنند. با استفاده از این امضاها اصلا نیازی به اعداد تصادفی نداریم، زیرا همهی امضاهای بلاک میتواند درون یک امضا ترکیب شده، چندامضایی m از n بسیار ساده است و به چند دور ارتباط و تعامل میان امضاکنندگان شبکه نیازی ندارد. علاوه بر این، امضاهای BLS دو برابر کوچکتر از امضاهای اشنور یا ECDSA هستند، چون این امضاها نه یک جفت، بلکه یک نقطهی منحنیاند. اکنون بگذارید ببینیم این امضاها چگونه کار میکنند.
جادوی امضای BLS
پیش از شروع به دو ساختار جدید نیاز داریم: هش منحنی و جفتسازی منحنی.
هش منحنی (Hashing to the curve)
ما در ECDSA و اشنور معمولا پیغام را هش کرده و از این هش به عنوان عددی در الگوریتم امضا استفاده میکنیم. ولی برای امضای BLS به الگوریتم هش نسبتا متفاوتی نیاز داریم که داخل منحنی بیضوی را هش کند. سادهترین راه این است که پیغام را مطابق معمول هش کرده و با نتیجهی آن مثل مختصات محور x از یک نقطه برخورد کنیم. منحنیهای بیضوی (مثل منحنی خاصی که در بیت کوین استفاده میشود) معمولا ۲۲۵۶ نقطه دارد و الگوریتم هش SHA-256 نیز نتیجهای به طول ۲۵۶ بیت بر میگرداند. ولی برای هر مختصات x دو نقطه با مختصات مثبت و منفیِ y وجود دارد (چون اگر (x,y) در منحنی y²=x³+ax+b باشد، پس (x,-y) هم روی همین منحنی است). این یعنی احتمال پیدا شدن دو نقطه برای x حدود ۵۰ درصد است.
به منظور یافتن نقطهای برای هر پیغام میتوانیم چند بار این الگوریتم هش را امتحان کرده و هر بار عددی را به آن اضافه کنیم. اگر (hash(m||0نقطهای را پیدا نکرد، آنگاه (hash(m||1 و (hash(m||2 و به همین ترتیب اعداد بعدی را امتحان میکنیم تا در نهایت به مقداری برسیم که با نقطهی ما مطابقت داشته باشد. سپس یکی از دو نقطهی متناظر را انتخاب کرده (فرض میکنیم نقطهی دارای y کوچکتر را انتخاب نموده) و بعد کار تمام است.
جفت سازی منحنی (Curves pairing)
مورد دیگری که لازم داریم، تابع بسیار ویژهای است که دو نقطه P و Q را به یک منحنی (یا دو منحنی متفاوت) میبرد و آنها را به یک عدد وصل میکند:
e(P, Q) → n
علاوه بر این، لازم است این تابع یک ویژگی مهم دیگر هم داشته باشد. اگر عدد محرمانهای تحت عنوان x و دو نقطهی P و Q داشته باشیم، باید صرفنظر از نقطهای که این عدد را در آن ضرب میکنیم، نتیجه یکسانی به دست بیاید:
(e(x×P, Q) = e(P, x×Q
اساسا باید بتوانیم ضریب افزایش نقاط را بدون تغییر نتیجه بین این دو آرگومان جابجا کنیم. به عبارت دیگر، تمام این جابجاییها باید نتیجهی یکسانی داشته باشد:
(e(a×P, b×Q) = e(P, ab×Q) = e(ab×P, Q) = e(P, Q)^(ab
در اینجا نمیخواهم چگونگی عملکرد این تابع را توضیح دهم. ریاضی پشت این تابع بسیار پیچیده است و چارهای جز عبور از آن نداریم. در حال حاضر صرفا میخواهیم قبول کنیم که این تابع وجود دارد و هیچ اطلاعاتی درباره عدد محرمانهی x فاش نمیکند.
نکتهی حائز اهمیت این است که ما در اینجا نمیتوانیم از منحنیهای بیضوی استفاده کنیم. پس برای این که بتوانیم کارآمدی این تابع را افزایش دهیم و آن را ایمن سازیم باید از منحنی بسیار خاصی از خانوادهی منحنیهای جفتساز استفاده کنیم.
سازوکار امضای BLS
اکنون تمام آنچه را که برای ساخت امضای BLS لازم است داریم. طبق معمول، کلید خصوصی ما عددی محرمانه مثل pk، کلید عمومی ما P = pk×G و پیغام ما m است.
حالا برای محاسبهی امضا ابتدا باید پیغام خود را بر منحنی m) H) هش کرده و نقطهی نتیجه را در کلید خصوصی (S = pk×H(m ضرب کنیم. همین! دیگر نه احتیاجی به اعداد تصادفی داریم و نه عملیاتهای اضافه! امضای ما فقط یک نقطهی منفرد بر روی منحنی است که در فرمت فشرده صرفا ۳۳ بایت فضا میگیرد.
تولید امضای BLS. برای تولید امضا هش پیام را در کلید خصوصی ضرب میکنیم.
کاربران برای تایید این امضا کافی است کلید عمومی ما را داشته باشند و آن را بررسی کنند.
(e(P, H(m)) = e(G, S
خروجی این فرمول به خاطر شاخصهی خوبی از تابع جفتسازی که در بالا به آن اشاره کردیم صحیح است:
(e(P, H(m)) = e(pk×G, H(m)) = e(G, pk×H(m)) = e(G, S
فرآیند تایید امضای BLS. کافی است ببینیم کلید عمومی و هش پیام مشابه نقطهی سازندهی منحنی و امضای آن به هم وصل شدهاند یا نه.
سازوکار این امضا زیبا و ساده است، ولی ویژگیهای بسیار جذابی، خصوصا برای بیت کوین، دارد.
تراکم امضا
اکنون بگذارید تمام امضاهای داخل بلاک را ترکیب کنیم! فرض کنید بلاکی با ۱۰۰۰ تراکنش داریم و هر تراکنش حاوی امضای Si، کلید عمومی Pi و پیامی است که با mi امضا شده. اگر بتوانیم آنها را با هم ترکیب کنیم، چه نیازی به ذخیرهسازی جداگانهشان داریم؟ فراموش نکنیم که برای ما فقط مهم است که امضاهای داخل بلاک معتبر باشد. امضای متراکم مجموعی از تمام امضاهای داخل بلاک است:
S = S1+S2+…+S1000
برای تایید بلاک باید مطمئن شویم که معادلهی زیر صدق میکند:
(e(G, S) = e(P1, H(m1))⋅e(P2, H(m2))⋅…⋅e(P1000, H(m1000)
اگر دقیق به این معادله نگاه کنید، میبینید که شروط آن واقعا صدق میکند:
اکنون همچنان باید تمام کلیدهای عمومی را بدانیم و ۱۰۰۱ تابع جفتسازی را محاسبه کنیم، اما در این حالت حداقل تمام امضاها فقط ۳۳ بایت فضا اشغال میکند. تراکم امضا میتواند توسط ماینرها انجام شده و صرفهجویی بسیاری در فضای ذخیرهسازی بلاکها داشته باشد.
تراکم کلید و چندامضایی n از n
اگر از آدرسهای چندامضایی استفاده میکنیم، یعنی یک تراکنش را با چند کلید امضا میکنیم. پس میتوانیم مثل سازوکار اشنور تراکم کلید داشته باشیم، یعنی تمام امضاها و کلیدها را درون جفتی تنها از یک کلید و یک امضا ترکیب کنیم. اکنون فرض کنید در یک مثال چندامضایی ۳ از ۳ امضا داشته باشیم.
یک روش ساده برای ترکیب این امضا این است که تمام امضاها و کلیدها را کنار هم اضافه کنیم. نتیجه میشود امضایی که S=S1+S2+S3 و کلیدی که P=P1+P2+P3 خواهد بود. بدیهی است که در این حالت همان معادلهی تایید قبلی باز هم کار میکند:
د
درست مثل اشنور در اینجا هم باید از خودمان در برابر حملهی کلید یاغی محافظت کنیم. برای انجام این کار یا باید از هر امضاکنندهی مشترک بخواهیم (با امضا کردن کلیدهای عمومی) ثابت کند که برای کلیدهای عمومیاش کلید خصوصی دارد، یا روندی غیرخطی به طرح خود اضافه کنیم و حملهی کلید یاغی را غیرممکن سازیم. پس به جای این که تمام کلیدها و امضاها را جمع کنیم، صرفا آنها را در یک عدد خاص ضرب میکنیم و بعد عمل زیر را انجام میدهیم:
S = a1×S1+a2×S2+a3×S3
P = a1×P1+a2×P2+a3×P3
در اینجا، ضرایب امضاها و کلیدها به صورت جدا از کلید عمومی امضاکننده و سایر کلیدهای عمومی محاسبه میشود:
({ai = hash(Pi, {P1,P2,P3
برای مثال این فرآیند ممکن است صرفا الحاقی از کلید عمومی امضاکننده و مجموعهی کاملی از کلیدهای عمومی خاصی باشد که از آنها در فرآیند امضا استفاده شده است: (ai = hash(Pi||P1||P2||P3.
در این حالت هم همان معادلهی تایید صدق میکند. البته ضریب ai به اثبات ما اضافه میشود، اما منطق آن به همان شکل قبلی باقی میماند.
نکته مثبت این سازوکار این است که لازم نیست چند بار بین دستگاههای مختلف ارتباط برقرار کنید. فقط باید بدانید سایر امضاکنندگان چه کسانی هستند. این روش نسبت به روش چندامضاییِ سه مرحلهایِ امضاهای اشنور خیلی سادهتر است. بهعلاوه، در این سازوکار هیچ نیازی به تصادفی بودن نداریم، چون همه چیز کاملا بر اساس یک الگوریتم مشخص انجام میشود.
روش چندامضایی زیرگروه (m از n امضا)
گاهی اوقات نمیخواهیم از روش چندامضایی n از n استفاده کنیم و ترجیح میدهیم m از n، مثلا ۲ از ۳ امضا، داشته باشیم. این یعنی نمیخواهیم تمام پولمان را از دست بدهیم، صرفا چون یکی از کلیدها گم شده است. در این سناریو توصیه میشود که از روش تراکم کلید استفاده کنید. این روش کارآمدترین روش ممکن نیست، ولی به نحوی کار میکند. با این حال، متاسفانه به محض این که به سراغ مقادیر بالای m و n بروید، اندازهی درخت مرکل به شکل نمایی افزایش چشمگیری پیدا میکند.
در روش امضای BLS یک سازوکار دیگر هم وجود دارد. البته این سیستم آن قدرها ساده نیست. در این راهکار به تابع هش نرمالی نیاز داریم که عددی را برگرداند. بهعلاوه، لازم است مرحلهای برای پیکربندی داشته باشیم تا تصمیم بگیریم که چه زمانی میخواهیم از چندامضایی استفاده کنیم. در این روش نیازی به ارتباطات اضافه نداریم و فقط کافی است از امضاها برای امضا کردن تراکنشها استفاده کنیم.
مثلا فرض کنیم دوباره میخواهیم طرحی چندامضایی به صورت ۲ از ۳ داشته باشیم که کلیدهای آن در ۳ دستگاه مختلف ذخیره شده باشد.
مرحله پیکربندی
هر یک از دستگاههای امضاکننده عددی مخصوص i = 1,2,3 دارد که جایگاه آن را در میان مجموعهای از دستگاهها، کلید خصوصی pki و کلید عمومی متناظر آن یعنی Pi = pki×G نشان میدهد. ما این کلید متراکم را دقیقا به همان روش قبلی محاسبه میکنیم:
({P = a1×P1+a2×P2+a3×P3, ai = hash(Pi, {P1,P2,P3
حالا تمام دستگاهها باید تایید کنند که عدد i عضوی از کلید عمومی متراکم (برای هر i) است. سپس این امضاها را جمع کرده و نتیجه را در دستگاه متناظر ذخیره کند:
(۰MKi = (a1⋅pk1)×H(P, i)+(a2⋅pk2)×H(P, i)+(a3⋅pk3)×H(P, i
ما این امضا را «کلید عضویت» مینامیم و بعدا در امضای خود از آن استفاده میکنیم. هر کلید عضویت یک امضای معتبر n از n از پیام H(P,i) است، یعنی:
((e(G, MKi)=e(P, H(P,i
این معادله را به یاد داشته باشید، چون بعدا به آن نیاز داریم. از این معادله استفاده خواهیم کرد تا ثابت کنیم که ما از مشارکتکنندگان معتبر طرح چندامضایی هستیم.
امضا کردن
حالا فرض کنید میخواهیم تراکنش را صرفا با کلیدهای pk1 و pk3 امضا کنیم. در این حالت باید دو امضای S1 و S3 بسازیم:
S1 = pk1×H(P, m)+MK1, S3=pk3×H(P, m)+MK3
و آنها را با هم جمع کنیم تا یک امضا و کلید منفرد به دست آوریم:
(S’, P’) = (S1+S3, P1+P3)
در معادلهی بالا P’ و S’ را نوشتم تا تاکید کنم که این کلید و امضا فقط توسط زیرگروهی از امضاکنندگان امضا شده و این قضیه مثل P نیست که کلیدی متراکم برای تمام امضاکنندگان است. برای تایید این امضای ۲ از ۳ باید بررسی کنیم که:
((e(G, S’) = e(P’, H(P, m))⋅e(P, H(P, 1)+H(P, 3
به خاطر داریم که کلیدهای عضویت MK1 و MK3 امضاهای معتبری برای پیامهای (H(P, 1 و (H(P, 3 است که توسط کلید متراکم P امضا شده، پس:
کار تمام است. این فرآیند نسبت به مدل n از n پیچیدهتر اما همچنان قابل فهم بود.
پیادهسازی احتمالی
برای پیادهسازی این طرح چندامضایی باید برای آدرس متناظر با کلید عمومی متراکم P پول بفرستیم و بگوییم که حداقل به دو امضا نیاز داریم. در زبان اسکریپتنویسی بیت کوین به روش زیر میتوانید اسکریپتها را قفل کنید:
OP_2 <P> OP_CHECK_BLS_MULTISIG
در اینجا OP_2 میگوید برای امضای این پیغام به دو کلید نیاز داریم. از آنجایی که در هیچجا نگفتهایم که مجموعاً ۳ امضاکننده وجود دارد، بنابراین هیچکس نمیتواند بگوید که آدرس چندامضایی ما ۲ از ۳ است یا ۲ از ۱۰۰. این اطلاعات را بعداً هم افشا نخواهیم کرد.
برای استفاده از این خروجی باید کلید P’، امضای S’ و شاخص امضاکنندگان را فراهم کنیم. پس در نمونهی ۱ از ۳، برای اسکریپت قفلگشایی چیزی شبیه کد زیر خواهیم داشت:
OP_1 OP_3 <P’> <S’>
ترکیب همهی این اسکریپتها آنچه را که میخواهیم در اختیار ما قرار میدهد. از روی OP_1 و OP_3 میدانیم که باید هش H(P, 1) و H(P, 3) را حساب کرده و بعد تمام چیزی که برای تایید تراکنش لازم است آماده میشود.
این یعنی برای هر m و n فقط به موارد زیر نیاز داریم:
- یک کلید عمومی متراکم P در اسکریپت قفل کردن
- یک کلید عمومی متراکم از امضاکنندگان P’
- یک امضای متراکم S’
- تعداد m با شاخص امضاکنندگان آن
در این روش همه چیز فشرده و زیباس! فقط یک نکته وجود دارد که من را آزار میدهد…همه ما معمولا فقط یک بار از آدرسها استفاده میکنیم؛ ما از مشتقات کلید مثل BIP32 برای ایجاد کلیدها و آدرسهای خصوصی کمک میگیریم. ولی برای هر مجموعهی جدید از کلیدهای خصوصی به مجموعهای از کلیدهای عضویت جدید نیاز داریم. یکی از روشهای انجام این کار، بدون این که هر دفعه وارد مرحلهی پیکربندی شویم، این است که دستهای از کلیدها، مثلا ۱۰۰۰ عدد از آنها، را بسازیم و کلیدهای عضویت متناظرشان را دریافت کنیم. از این به بعد تنها زمانی وارد مرحلهی پیکربندی میشویم که تمام آن ۱۰۰۰ آدرس استفاده شده باشد.
نقاط ضعف
جفتسازی در این روش سخت است. در بخشهای قبلی به این موضوع اشاره نکردیم، اما اکنون باید به این موضوع اذعان کنیم تا گمان نکنید که تابع جادویی e(P, Q) آن قدرها ایدهآل و ایمن است.
- جفتسازی آن قدرها کارآمد نیست
تایید امضای BLS از نظر سختی دشوارتر از ECDSA است. تراکم امضا برای بلاکی با ۱۰۰۰ تراکنش همچنان نیازمند پردازش ۱۰۰۰ عملیات جفتسازی است، پس تایید یک امضای کوچک در داخل یک بلاک ممکن است بیشتر از تایید ۱۰۰۰ امضای جداگانهی ECDSA طول بکشد. تنها مزیت این روش در آن است که میتوانیم تراکنشهای بیشتری را در بلاک جا دهیم چون امضای متراکم فقط ۳۳ بایت فضا میگیرد.
امضاهای اشنور برخلاف امضاهای BLS بسیار کارآمدند. در سیستم اشنور میتوانید همهی امضاها را در کنار یکدیگر تایید کنید و این پروسه ۳ برابر بیشتر از ECDSA کارآمد است. ولی سوال مهمی که باید به دنبال پاسخش باشیم این است که کدام مسئله اهمیت بیشتری برای ما دارد؟
- اثبات امنیت سختتر است
توابع جفتسازی پیچیدهاند و اگر مراقب نباشیم ممکن است ما را به دردسر بیندازند. ما از یک سو میخواهیم فرآیند جفتسازی کارآمد باشد تا بتوانیم سریعتر امضاها را تایید کنیم، اما از سوی دیگر نمیخواهیم هیچ اطلاعاتی دربارهی کلید خصوصی ما لو برود. این دو پیشنیاز با یکدیگر تداخل دارند، به همین خاطر در هنگام انتخاب منحنیهای جفتسازی باید بسیار مواظب باشیم.
نوعی حمله در سیستمهای کریپتویی منحنی بیضوی به نام حمله Menezes-Okamoto-Vanstone) MOV) وجود دارد که با استفاده از تابع جادویی ما امنیت سیستم را پایین میآورد. بنابراین باید خیلی مراقب باشیم.
جمعبندی
امضاهای BLS فوق العادهاند. میتوانیم همه امضاهای داخل بلاک را با این روش درون یک امضای تنها ترکیب کنیم، میتوانیم بدون نیاز به مراتب اضافهی ارتباط از روش تراکم کلید و طرح چندامضایی m از n استفاده کنیم، لازم نیست به مولدهای اعداد تصادفی اتکا کنیم، و با یک نگاه به این سیستم میتوانیم بفهمیم که با راهکاری ساده و مناسب طرف هستیم. البته هنوز جا برای پیشرفت وجود دارد، اما استانداردسازی و بهینهسازی همهی بخشهای این روش کمی زمان میبرد. با این حال میتوانیم امید داشته باشیم که این روش در آینده آن قدر خوب شود که بیت کوین از آن استفاده کند و بتوانیم از ویژگیهای جذابش بهرهمند شویم.