Prehash এবং SignPrehash প্রিমিটিভগুলো একটি ডিজিটাল স্বাক্ষরের গণনাকে দুটি ধাপে বিভক্ত করে:
- প্রিহ্যাশের জন্য শুধুমাত্র পাবলিক কী প্রয়োজন। এটি যেকোনো দৈর্ঘ্যের একটি মেসেজকে একটি সংক্ষিপ্ত, নির্দিষ্ট আকারের প্রিহ্যাশ ভ্যালুতে রূপান্তরিত করে।
- SignPrahash-এর জন্য প্রাইভেট কী প্রয়োজন। এটি একটি প্রিহ্যাশ ভ্যালুকে সিগনেচারে রূপান্তরিত করে।
যে সিগনেচারটি তৈরি হয়, তা মূল মেসেজের উপর করা একটি সাধারণ সিগনেচার। আপনি সাধারণ ডিজিটাল সিগনেচার PublicKeyVerify প্রিমিটিভ ব্যবহার করে এটি ভেরিফাই করেন, এবং ভেরিফায়ারদের এটা জানার বা এতে মাথা ঘামানোর প্রয়োজন নেই যে সিগনেচারটি দুটি ধাপে তৈরি করা হয়েছে।
প্রিহ্যাশ ভ্যালুটিকে অপাক বাইট হিসেবে বিবেচনা করুন। এর একটি নির্দিষ্ট আকার আছে এবং এটি যে কী-এর জন্য গণনা করা হয়েছে তার আইডি বহন করে, কিন্তু এর লেআউটটি টিঙ্ক-এর ওয়্যার ফরম্যাটের একটি অংশ, এবং আপনার নিজে থেকে এটি পার্স বা তৈরি করা উচিত নয়। আপনি যদি টিঙ্ক পোর্ট করেন বা বাইট-স্তরের বিশদ বিবরণের প্রয়োজন হয়, তবে টিঙ্ক ওয়্যার ফরম্যাট দেখুন।
এই জোড়া প্রিমিটিভ কখন ব্যবহার করবেন:
- সাইনিং কী-টি অন্য কোথাও থাকে , যেমন একটি HSM-এ, একটি KMS-এ, বা একটি RPC বাউন্ডারির পিছনে, এবং আপনি সেই বাউন্ডারির ওপার থেকে সম্পূর্ণ মেসেজটি পাঠাতে চাইবেন না।
- বার্তাটি বড় , এবং দূরবর্তী স্বাক্ষরকারী অনুরোধের আকারের উপর একটি সীমা আরোপ করে।
যদি এর কোনোটিই প্রযোজ্য না হয়, তাহলে এর পরিবর্তে সাধারণ ডিজিটাল সিগনেচার প্রিমিটিভটি ব্যবহার করুন: এটি আরও সরল এবং এর অপব্যবহার করাও কঠিন।
কীসেট
এই দুটি প্রিমিটিভ ভিন্নভাবে কী নির্বাচন করে, ঠিক যেমনভাবে ডিজিটাল সিগনেচার প্রিমিটিভের জন্য সাইনিং এবং ভেরিফিকেশন কাজ করে থাকে:
-
Prehash.Computeসর্বদা পাবলিক কীসেটের প্রাইমারি কী ব্যবহার করে এবং প্রিহ্যাশ ভ্যালুতে সেই কী-এর আইডি রেকর্ড করে। কোন কী দিয়ে সিগনেচার তৈরি করা হবে, তা এই পক্ষই নির্বাচন করে । -
SignPrehash.Signপ্রিহ্যাশ ভ্যালু থেকে কী আইডিটি পড়ে নেয় এবং প্রাইভেট কীসেটের সাথে মিলে যাওয়া সক্রিয় কী দিয়ে সাইন করে। এটি সেই অংশ যা অন্য কারো করা পছন্দকে অনুসরণ করে । যদি কীসেটের কোনো সক্রিয় কী-তে সেই আইডিটি না থাকে, তাহলে কলটি ব্যর্থ হয়।
একটি SignPreahash কীসেটের প্রতিটি কী-এর একটি আইডি থাকা আবশ্যক, অন্যথায় প্রিমিটিভটি তৈরি করা ব্যর্থ হয়।
ন্যূনতম নিরাপত্তা গ্যারান্টি
- ফলস্বরূপ প্রাপ্ত স্বাক্ষরটির বৈশিষ্ট্যগুলো, একই কী টাইপ ব্যবহার করে ডিজিটাল সিগনেচার প্রিমিটিভ দ্বারা তৈরি স্বাক্ষরের বৈশিষ্ট্যের অনুরূপ হয়।
- Tink প্রিহ্যাশ ভ্যালুর শুরুতে ৫ বাইট যোগ করে, যার মধ্যে একটি বিশেষ সংরক্ষিত ভ্যালু এবং যে কী-এর জন্য এটি গণনা করা হয়েছে তার আইডি থাকে।
SignPrehashশুধুমাত্র সেই কী দিয়েই ভ্যালুটিকে সাইন করে। ভ্যালুটি ক্রিপ্টোগ্রাফিকভাবে সেই কী-এর সাথে আবদ্ধ থাকবে কিনা তা অ্যালগরিদমের উপর নির্ভর করে; External Mu ML-DSA-এর ক্ষেত্রে এটি আবদ্ধ থাকে, Tink wire format দেখুন। - বার্তার দৈর্ঘ্য ইচ্ছামতো হতে পারে।
যেসব বিষয়ে সতর্ক থাকতে হবে
- স্বাক্ষরকারী যা স্বাক্ষর করে তা পরিদর্শন করতে পারে না। যে কেউ
SignPrehashকল করতে পারলেই যেকোনো বার্তা স্বাক্ষর করিয়ে নিতে পারে, এবং স্বাক্ষরকারীর কাছে বার্তার বিষয়বস্তুর উপর কোনো নীতি প্রয়োগ করার উপায় থাকে না।SignPrehashএর অ্যাক্সেসকে ঠিক সেভাবেই সুরক্ষিত করুন, যেভাবে আপনিPublicKeySignএর অ্যাক্সেসকে সুরক্ষিত করেন। - স্থানান্তরের সময় প্রিহ্যাশ মানটি সুরক্ষিত রাখুন। এটি গোপনীয় নয়, কিন্তু একজন আক্রমণকারী যিনি স্থানান্তরের সময় এটি পরিবর্তন করতে পারেন, তিনি নিয়ন্ত্রণ করেন যে কী স্বাক্ষরিত হবে।
একটি কী-টাইপ বেছে নিন
RFC 9881- এ বর্ণিত এক্সটার্নাল মু মোডে থাকা ML-DSA-ই একমাত্র অ্যালগরিদম যা Tink, Prehash এবং SignPrehash-এর জন্য সমর্থন করে। এই প্রিমিটিভগুলোর সাথে আপনার একটি স্ট্যান্ডার্ড ML-DSA কী ব্যবহার করা উচিত।
অধিকাংশ ব্যবহারের ক্ষেত্রে আমরা ML_DSA_65 সুপারিশ করি।
কী-টির একটি আইডি থাকা আবশ্যক, কারণ প্রতিটি প্রিহ্যাশ ভ্যালু একটি প্রিফিক্স দিয়ে শুরু হয়, যেটিতে সেই কী-টির আইডি থাকে যার জন্য এটি গণনা করা হয়েছে। নিম্নলিখিত ভ্যারিয়েন্টগুলো গ্রহণযোগ্য:
-
TINK-- ফলস্বরূপ সিগনেচারটি Tink-এর সাধারণ ৫-বাইট আউটপুট প্রিফিক্স দিয়ে শুরু হয়। -
NO_PREFIX_WITH_PREHASH_ID-- এর ফলে প্রাপ্ত সিগনেচারে কোনো আউটপুট প্রিফিক্স থাকে না, কিন্তু কী-টিতে সেই আইডিটি থাকে যা প্রিহ্যাশ ভ্যালুর জন্য প্রয়োজন।
NO_PREFIX (raw) ভ্যারিয়েন্ট ব্যবহার করা কীগুলো সমর্থিত নয়, কারণ সেগুলোর কোনো কী আইডি নেই।
উদাহরণ
নিম্নলিখিত উদাহরণগুলিতে দুটি ধাপে একটি বার্তা স্বাক্ষর করা হয় এবং তারপরে সাধারণ ডিজিটাল স্বাক্ষর প্রিমিটিভ ব্যবহার করে প্রাপ্ত স্বাক্ষরটি যাচাই করা হয়।
পাঠযোগ্যতার জন্য এগুলোকে একটি ব্লক হিসেবে দেখানো হয়। বাস্তব প্রয়োগে এই দুটি ধাপ ভিন্ন ভিন্ন স্থানে চলে; ধাপে ধাপে নির্দেশনার জন্য "আমি একজন রিমোট সাইনারের মাধ্যমে ডেটা স্বাক্ষর করতে চাই" দেখুন।
সি++
#include "tink/keyset_handle.h" #include "tink/public_key_verify.h" #include "tink/signature/config_2026.h" #include "tink/signature/prehash.h" #include "tink/signature/sign_prehash.h" using ::crypto::tink::ConfigSignature2026; using ::crypto::tink::Prehash; using ::crypto::tink::PublicKeyVerify; using ::crypto::tink::SignPrehash; // 1. Wherever the message is: compute the prehash value. This needs only // the public keyset. absl::StatusOr<std::unique_ptr<Prehash>> prehasher = public_handle.GetPrimitive<Prehash>(ConfigSignature2026()); if (!prehasher.ok()) return prehasher.status(); absl::StatusOr<std::string> prehash = (*prehasher)->Compute(message); if (!prehash.ok()) return prehash.status(); // 2. Wherever the private key is: turn the prehash value into a signature. absl::StatusOr<std::unique_ptr<SignPrehash>> signer = private_handle.GetPrimitive<SignPrehash>(ConfigSignature2026()); if (!signer.ok()) return signer.status(); absl::StatusOr<std::string> signature = (*signer)->Sign(*prehash); if (!signature.ok()) return signature.status(); // 3. Anywhere: verify the signature over the original message. absl::StatusOr<std::unique_ptr<PublicKeyVerify>> verifier = public_handle.GetPrimitive<PublicKeyVerify>(ConfigSignature2026()); if (!verifier.ok()) return verifier.status(); absl::Status verified = (*verifier)->Verify(*signature, message);
যান
import ( "github.com/tink-crypto/tink-go/v2/signature" "github.com/tink-crypto/tink-go/v2/signprehash" ) // 1. Wherever the message is: compute the prehash value. This needs only // the public keyset. prehasher, err := signprehash.NewPrehash(publicHandle) if err != nil { return err } prehash, err := prehasher.ComputePrehash(message) if err != nil { return err } // 2. Wherever the private key is: turn the prehash value into a signature. signer, err := signprehash.NewPrehashSigner(privateHandle) if err != nil { return err } sig, err := signer.SignPrehash(prehash) if err != nil { return err } // 3. Anywhere: verify the signature over the original message. verifier, err := signature.NewVerifier(publicHandle) if err != nil { return err } if err := verifier.Verify(sig, message); err != nil { return err }
পাইথন
from tink import signature # Needed for PublicKeyVerify in step 3. Due to the internal structure of # Tink Python, Prehash and SignPrehash are an exception where calling # signature.register() is not necessary; do not expect the same for other # primitives. signature.register() # 1. Wherever the message is: compute the prehash value. This needs only # the public keyset. prehasher = public_handle.primitive(signature.Prehash) prehash = prehasher.compute(message) # 2. Wherever the private key is: turn the prehash value into a signature. signer = private_handle.primitive(signature.SignPrehash) sig = signer.sign(prehash) # 3. Anywhere: verify the signature over the original message. verifier = public_handle.primitive(signature.PublicKeyVerify) verifier.verify(sig, message)
সম্পর্কিত বিষয়
- আমি একজন দূরবর্তী স্বাক্ষরকারীর মাধ্যমে ডেটা স্বাক্ষর করতে চাই — এই দুই-ধাপের কার্যপ্রবাহের একটি ধাপে ধাপে বিবরণ।
- ডিজিটাল স্বাক্ষর — এক ধাপেই স্বাক্ষর ও যাচাই করা যায়, এবং স্বাক্ষরকারী বার্তাটি দেখতে পারেন।
- ভাষা অনুযায়ী সমর্থিত প্রিমিটিভ কী-এর প্রকারভেদ
- টিঙ্ক ওয়্যার ফরম্যাট — একটি প্রিহ্যাশ মানের বাইট-স্তরের বিন্যাস, যা টিঙ্ককে অন্য কোনো ভাষায় পোর্ট করার জন্য ব্যবহৃত হয়।
Prehash এবং SignPrehash প্রিমিটিভগুলো একটি ডিজিটাল স্বাক্ষরের গণনাকে দুটি ধাপে বিভক্ত করে:
- প্রিহ্যাশের জন্য শুধুমাত্র পাবলিক কী প্রয়োজন। এটি যেকোনো দৈর্ঘ্যের একটি মেসেজকে একটি সংক্ষিপ্ত, নির্দিষ্ট আকারের প্রিহ্যাশ ভ্যালুতে রূপান্তরিত করে।
- SignPrahash-এর জন্য প্রাইভেট কী প্রয়োজন। এটি একটি প্রিহ্যাশ ভ্যালুকে সিগনেচারে রূপান্তরিত করে।
যে সিগনেচারটি তৈরি হয়, তা মূল মেসেজের উপর করা একটি সাধারণ সিগনেচার। আপনি সাধারণ ডিজিটাল সিগনেচার PublicKeyVerify প্রিমিটিভ ব্যবহার করে এটি ভেরিফাই করেন, এবং ভেরিফায়ারদের এটা জানার বা এতে মাথা ঘামানোর প্রয়োজন নেই যে সিগনেচারটি দুটি ধাপে তৈরি করা হয়েছে।
প্রিহ্যাশ ভ্যালুটিকে অপাক বাইট হিসেবে বিবেচনা করুন। এর একটি নির্দিষ্ট আকার আছে এবং এটি যে কী-এর জন্য গণনা করা হয়েছে তার আইডি বহন করে, কিন্তু এর লেআউটটি টিঙ্ক-এর ওয়্যার ফরম্যাটের একটি অংশ, এবং আপনার নিজে থেকে এটি পার্স বা তৈরি করা উচিত নয়। আপনি যদি টিঙ্ক পোর্ট করেন বা বাইট-স্তরের বিশদ বিবরণের প্রয়োজন হয়, তবে টিঙ্ক ওয়্যার ফরম্যাট দেখুন।
এই জোড়া প্রিমিটিভ কখন ব্যবহার করবেন:
- সাইনিং কী-টি অন্য কোথাও থাকে , যেমন একটি HSM-এ, একটি KMS-এ, বা একটি RPC বাউন্ডারির পিছনে, এবং আপনি সেই বাউন্ডারির ওপার থেকে সম্পূর্ণ মেসেজটি পাঠাতে চাইবেন না।
- বার্তাটি বড় , এবং দূরবর্তী স্বাক্ষরকারী অনুরোধের আকারের উপর একটি সীমা আরোপ করে।
যদি এর কোনোটিই প্রযোজ্য না হয়, তাহলে এর পরিবর্তে সাধারণ ডিজিটাল সিগনেচার প্রিমিটিভটি ব্যবহার করুন: এটি আরও সরল এবং এর অপব্যবহার করাও কঠিন।
কীসেট
এই দুটি প্রিমিটিভ ভিন্নভাবে কী নির্বাচন করে, ঠিক যেমনভাবে ডিজিটাল সিগনেচার প্রিমিটিভের জন্য সাইনিং এবং ভেরিফিকেশন কাজ করে থাকে:
-
Prehash.Computeসর্বদা পাবলিক কীসেটের প্রাইমারি কী ব্যবহার করে এবং প্রিহ্যাশ ভ্যালুতে সেই কী-এর আইডি রেকর্ড করে। কোন কী দিয়ে সিগনেচার তৈরি করা হবে, তা এই পক্ষই নির্বাচন করে । -
SignPrehash.Signপ্রিহ্যাশ ভ্যালু থেকে কী আইডিটি পড়ে নেয় এবং প্রাইভেট কীসেটের সাথে মিলে যাওয়া সক্রিয় কী দিয়ে সাইন করে। এটি সেই অংশ যা অন্য কারো করা পছন্দকে অনুসরণ করে । যদি কীসেটের কোনো সক্রিয় কী-তে সেই আইডিটি না থাকে, তাহলে কলটি ব্যর্থ হয়।
একটি SignPreahash কীসেটের প্রতিটি কী-এর একটি আইডি থাকা আবশ্যক, অন্যথায় প্রিমিটিভটি তৈরি করা ব্যর্থ হয়।
ন্যূনতম নিরাপত্তা গ্যারান্টি
- ফলস্বরূপ প্রাপ্ত স্বাক্ষরটির বৈশিষ্ট্যগুলো, একই কী টাইপ ব্যবহার করে ডিজিটাল সিগনেচার প্রিমিটিভ দ্বারা তৈরি স্বাক্ষরের বৈশিষ্ট্যের অনুরূপ হয়।
- Tink প্রিহ্যাশ ভ্যালুর শুরুতে ৫ বাইট যোগ করে, যার মধ্যে একটি বিশেষ সংরক্ষিত ভ্যালু এবং যে কী-এর জন্য এটি গণনা করা হয়েছে তার আইডি থাকে।
SignPrehashশুধুমাত্র সেই কী দিয়েই ভ্যালুটিকে সাইন করে। ভ্যালুটি ক্রিপ্টোগ্রাফিকভাবে সেই কী-এর সাথে আবদ্ধ থাকবে কিনা তা অ্যালগরিদমের উপর নির্ভর করে; External Mu ML-DSA-এর ক্ষেত্রে এটি আবদ্ধ থাকে, Tink wire format দেখুন। - বার্তার দৈর্ঘ্য ইচ্ছামতো হতে পারে।
যেসব বিষয়ে সতর্ক থাকতে হবে
- স্বাক্ষরকারী যা স্বাক্ষর করে তা পরিদর্শন করতে পারে না। যে কেউ
SignPrehashকল করতে পারলেই যেকোনো বার্তা স্বাক্ষর করিয়ে নিতে পারে, এবং স্বাক্ষরকারীর কাছে বার্তার বিষয়বস্তুর উপর কোনো নীতি প্রয়োগ করার উপায় থাকে না।SignPrehashএর অ্যাক্সেসকে ঠিক সেভাবেই সুরক্ষিত করুন, যেভাবে আপনিPublicKeySignএর অ্যাক্সেসকে সুরক্ষিত করেন। - স্থানান্তরের সময় প্রিহ্যাশ মানটি সুরক্ষিত রাখুন। এটি গোপনীয় নয়, কিন্তু একজন আক্রমণকারী যিনি স্থানান্তরের সময় এটি পরিবর্তন করতে পারেন, তিনি নিয়ন্ত্রণ করেন যে কী স্বাক্ষরিত হবে।
একটি কী-টাইপ বেছে নিন
RFC 9881- এ বর্ণিত এক্সটার্নাল মু মোডে থাকা ML-DSA-ই একমাত্র অ্যালগরিদম যা Tink, Prehash এবং SignPrehash-এর জন্য সমর্থন করে। এই প্রিমিটিভগুলোর সাথে আপনার একটি স্ট্যান্ডার্ড ML-DSA কী ব্যবহার করা উচিত।
অধিকাংশ ব্যবহারের ক্ষেত্রে আমরা ML_DSA_65 সুপারিশ করি।
কী-টির একটি আইডি থাকা আবশ্যক, কারণ প্রতিটি প্রিহ্যাশ ভ্যালু একটি প্রিফিক্স দিয়ে শুরু হয়, যেটিতে সেই কী-টির আইডি থাকে যার জন্য এটি গণনা করা হয়েছে। নিম্নলিখিত ভ্যারিয়েন্টগুলো গ্রহণযোগ্য:
-
TINK-- ফলস্বরূপ সিগনেচারটি Tink-এর সাধারণ ৫-বাইট আউটপুট প্রিফিক্স দিয়ে শুরু হয়। -
NO_PREFIX_WITH_PREHASH_ID-- এর ফলে প্রাপ্ত সিগনেচারে কোনো আউটপুট প্রিফিক্স থাকে না, কিন্তু কী-টিতে সেই আইডিটি থাকে যা প্রিহ্যাশ ভ্যালুর জন্য প্রয়োজন।
NO_PREFIX (raw) ভ্যারিয়েন্ট ব্যবহার করা কীগুলো সমর্থিত নয়, কারণ সেগুলোর কোনো কী আইডি নেই।
উদাহরণ
নিম্নলিখিত উদাহরণগুলিতে দুটি ধাপে একটি বার্তা স্বাক্ষর করা হয় এবং তারপরে সাধারণ ডিজিটাল স্বাক্ষর প্রিমিটিভ ব্যবহার করে প্রাপ্ত স্বাক্ষরটি যাচাই করা হয়।
পাঠযোগ্যতার জন্য এগুলোকে একটি ব্লক হিসেবে দেখানো হয়। বাস্তব প্রয়োগে এই দুটি ধাপ ভিন্ন ভিন্ন স্থানে চলে; ধাপে ধাপে নির্দেশনার জন্য "আমি একজন রিমোট সাইনারের মাধ্যমে ডেটা স্বাক্ষর করতে চাই" দেখুন।
সি++
#include "tink/keyset_handle.h" #include "tink/public_key_verify.h" #include "tink/signature/config_2026.h" #include "tink/signature/prehash.h" #include "tink/signature/sign_prehash.h" using ::crypto::tink::ConfigSignature2026; using ::crypto::tink::Prehash; using ::crypto::tink::PublicKeyVerify; using ::crypto::tink::SignPrehash; // 1. Wherever the message is: compute the prehash value. This needs only // the public keyset. absl::StatusOr<std::unique_ptr<Prehash>> prehasher = public_handle.GetPrimitive<Prehash>(ConfigSignature2026()); if (!prehasher.ok()) return prehasher.status(); absl::StatusOr<std::string> prehash = (*prehasher)->Compute(message); if (!prehash.ok()) return prehash.status(); // 2. Wherever the private key is: turn the prehash value into a signature. absl::StatusOr<std::unique_ptr<SignPrehash>> signer = private_handle.GetPrimitive<SignPrehash>(ConfigSignature2026()); if (!signer.ok()) return signer.status(); absl::StatusOr<std::string> signature = (*signer)->Sign(*prehash); if (!signature.ok()) return signature.status(); // 3. Anywhere: verify the signature over the original message. absl::StatusOr<std::unique_ptr<PublicKeyVerify>> verifier = public_handle.GetPrimitive<PublicKeyVerify>(ConfigSignature2026()); if (!verifier.ok()) return verifier.status(); absl::Status verified = (*verifier)->Verify(*signature, message);
যান
import ( "github.com/tink-crypto/tink-go/v2/signature" "github.com/tink-crypto/tink-go/v2/signprehash" ) // 1. Wherever the message is: compute the prehash value. This needs only // the public keyset. prehasher, err := signprehash.NewPrehash(publicHandle) if err != nil { return err } prehash, err := prehasher.ComputePrehash(message) if err != nil { return err } // 2. Wherever the private key is: turn the prehash value into a signature. signer, err := signprehash.NewPrehashSigner(privateHandle) if err != nil { return err } sig, err := signer.SignPrehash(prehash) if err != nil { return err } // 3. Anywhere: verify the signature over the original message. verifier, err := signature.NewVerifier(publicHandle) if err != nil { return err } if err := verifier.Verify(sig, message); err != nil { return err }
পাইথন
from tink import signature # Needed for PublicKeyVerify in step 3. Due to the internal structure of # Tink Python, Prehash and SignPrehash are an exception where calling # signature.register() is not necessary; do not expect the same for other # primitives. signature.register() # 1. Wherever the message is: compute the prehash value. This needs only # the public keyset. prehasher = public_handle.primitive(signature.Prehash) prehash = prehasher.compute(message) # 2. Wherever the private key is: turn the prehash value into a signature. signer = private_handle.primitive(signature.SignPrehash) sig = signer.sign(prehash) # 3. Anywhere: verify the signature over the original message. verifier = public_handle.primitive(signature.PublicKeyVerify) verifier.verify(sig, message)
সম্পর্কিত বিষয়
- আমি একজন দূরবর্তী স্বাক্ষরকারীর মাধ্যমে ডেটা স্বাক্ষর করতে চাই — এই দুই-ধাপের কার্যপ্রবাহের একটি ধাপে ধাপে বিবরণ।
- ডিজিটাল স্বাক্ষর — এক ধাপেই স্বাক্ষর ও যাচাই করা যায়, এবং স্বাক্ষরকারী বার্তাটি দেখতে পারেন।
- ভাষা অনুযায়ী সমর্থিত প্রিমিটিভ কী-এর প্রকারভেদ
- টিঙ্ক ওয়্যার ফরম্যাট — একটি প্রিহ্যাশ মানের বাইট-স্তরের বিন্যাস, যা টিঙ্ককে অন্য কোনো ভাষায় পোর্ট করার জন্য ব্যবহৃত হয়।
Prehash এবং SignPrehash প্রিমিটিভগুলো একটি ডিজিটাল স্বাক্ষরের গণনাকে দুটি ধাপে বিভক্ত করে:
- প্রিহ্যাশের জন্য শুধুমাত্র পাবলিক কী প্রয়োজন। এটি যেকোনো দৈর্ঘ্যের একটি মেসেজকে একটি সংক্ষিপ্ত, নির্দিষ্ট আকারের প্রিহ্যাশ ভ্যালুতে রূপান্তরিত করে।
- SignPrahash-এর জন্য প্রাইভেট কী প্রয়োজন। এটি একটি প্রিহ্যাশ ভ্যালুকে সিগনেচারে রূপান্তরিত করে।
যে সিগনেচারটি তৈরি হয়, তা মূল মেসেজের উপর করা একটি সাধারণ সিগনেচার। আপনি সাধারণ ডিজিটাল সিগনেচার PublicKeyVerify প্রিমিটিভ ব্যবহার করে এটি ভেরিফাই করেন, এবং ভেরিফায়ারদের এটা জানার বা এতে মাথা ঘামানোর প্রয়োজন নেই যে সিগনেচারটি দুটি ধাপে তৈরি করা হয়েছে।
প্রিহ্যাশ ভ্যালুটিকে অপাক বাইট হিসেবে বিবেচনা করুন। এর একটি নির্দিষ্ট আকার আছে এবং এটি যে কী-এর জন্য গণনা করা হয়েছে তার আইডি বহন করে, কিন্তু এর লেআউটটি টিঙ্ক-এর ওয়্যার ফরম্যাটের একটি অংশ, এবং আপনার নিজে থেকে এটি পার্স বা তৈরি করা উচিত নয়। আপনি যদি টিঙ্ক পোর্ট করেন বা বাইট-স্তরের বিশদ বিবরণের প্রয়োজন হয়, তবে টিঙ্ক ওয়্যার ফরম্যাট দেখুন।
এই জোড়া প্রিমিটিভ কখন ব্যবহার করবেন:
- সাইনিং কী-টি অন্য কোথাও থাকে , যেমন একটি HSM-এ, একটি KMS-এ, বা একটি RPC বাউন্ডারির পিছনে, এবং আপনি সেই বাউন্ডারির ওপার থেকে সম্পূর্ণ মেসেজটি পাঠাতে চাইবেন না।
- বার্তাটি বড় , এবং দূরবর্তী স্বাক্ষরকারী অনুরোধের আকারের উপর একটি সীমা আরোপ করে।
যদি এর কোনোটিই প্রযোজ্য না হয়, তাহলে এর পরিবর্তে সাধারণ ডিজিটাল সিগনেচার প্রিমিটিভটি ব্যবহার করুন: এটি আরও সরল এবং এর অপব্যবহার করাও কঠিন।
কীসেট
এই দুটি প্রিমিটিভ ভিন্নভাবে কী নির্বাচন করে, ঠিক যেমনভাবে ডিজিটাল সিগনেচার প্রিমিটিভের জন্য সাইনিং এবং ভেরিফিকেশন কাজ করে থাকে:
-
Prehash.Computeসর্বদা পাবলিক কীসেটের প্রাইমারি কী ব্যবহার করে এবং প্রিহ্যাশ ভ্যালুতে সেই কী-এর আইডি রেকর্ড করে। কোন কী দিয়ে সিগনেচার তৈরি করা হবে, তা এই পক্ষই নির্বাচন করে । -
SignPrehash.Signপ্রিহ্যাশ ভ্যালু থেকে কী আইডিটি পড়ে নেয় এবং প্রাইভেট কীসেটের সাথে মিলে যাওয়া সক্রিয় কী দিয়ে সাইন করে। এটি সেই অংশ যা অন্য কারো করা পছন্দকে অনুসরণ করে । যদি কীসেটের কোনো সক্রিয় কী-তে সেই আইডিটি না থাকে, তাহলে কলটি ব্যর্থ হয়।
একটি SignPreahash কীসেটের প্রতিটি কী-এর একটি আইডি থাকা আবশ্যক, অন্যথায় প্রিমিটিভটি তৈরি করা ব্যর্থ হয়।
ন্যূনতম নিরাপত্তা গ্যারান্টি
- ফলস্বরূপ প্রাপ্ত স্বাক্ষরটির বৈশিষ্ট্যগুলো, একই কী টাইপ ব্যবহার করে ডিজিটাল সিগনেচার প্রিমিটিভ দ্বারা তৈরি স্বাক্ষরের বৈশিষ্ট্যের অনুরূপ হয়।
- Tink প্রিহ্যাশ ভ্যালুর শুরুতে ৫ বাইট যোগ করে, যার মধ্যে একটি বিশেষ সংরক্ষিত ভ্যালু এবং যে কী-এর জন্য এটি গণনা করা হয়েছে তার আইডি থাকে।
SignPrehashশুধুমাত্র সেই কী দিয়েই ভ্যালুটিকে সাইন করে। ভ্যালুটি ক্রিপ্টোগ্রাফিকভাবে সেই কী-এর সাথে আবদ্ধ থাকবে কিনা তা অ্যালগরিদমের উপর নির্ভর করে; External Mu ML-DSA-এর ক্ষেত্রে এটি আবদ্ধ থাকে, Tink wire format দেখুন। - বার্তার দৈর্ঘ্য ইচ্ছামতো হতে পারে।
যেসব বিষয়ে সতর্ক থাকতে হবে
- স্বাক্ষরকারী যা স্বাক্ষর করে তা পরিদর্শন করতে পারে না। যে কেউ
SignPrehashকল করতে পারলেই যেকোনো বার্তা স্বাক্ষর করিয়ে নিতে পারে, এবং স্বাক্ষরকারীর কাছে বার্তার বিষয়বস্তুর উপর কোনো নীতি প্রয়োগ করার উপায় থাকে না।SignPrehashএর অ্যাক্সেসকে ঠিক সেভাবেই সুরক্ষিত করুন, যেভাবে আপনিPublicKeySignএর অ্যাক্সেসকে সুরক্ষিত করেন। - স্থানান্তরের সময় প্রিহ্যাশ মানটি সুরক্ষিত রাখুন। এটি গোপনীয় নয়, কিন্তু একজন আক্রমণকারী যিনি স্থানান্তরের সময় এটি পরিবর্তন করতে পারেন, তিনি নিয়ন্ত্রণ করেন যে কী স্বাক্ষরিত হবে।
একটি কী-টাইপ বেছে নিন
RFC 9881- এ বর্ণিত এক্সটার্নাল মু মোডে থাকা ML-DSA-ই একমাত্র অ্যালগরিদম যা Tink, Prehash এবং SignPrehash-এর জন্য সমর্থন করে। এই প্রিমিটিভগুলোর সাথে আপনার একটি স্ট্যান্ডার্ড ML-DSA কী ব্যবহার করা উচিত।
অধিকাংশ ব্যবহারের ক্ষেত্রে আমরা ML_DSA_65 সুপারিশ করি।
কী-টির একটি আইডি থাকা আবশ্যক, কারণ প্রতিটি প্রিহ্যাশ ভ্যালু একটি প্রিফিক্স দিয়ে শুরু হয়, যেটিতে সেই কী-টির আইডি থাকে যার জন্য এটি গণনা করা হয়েছে। নিম্নলিখিত ভ্যারিয়েন্টগুলো গ্রহণযোগ্য:
-
TINK-- ফলস্বরূপ সিগনেচারটি Tink-এর সাধারণ ৫-বাইট আউটপুট প্রিফিক্স দিয়ে শুরু হয়। -
NO_PREFIX_WITH_PREHASH_ID-- এর ফলে প্রাপ্ত সিগনেচারে কোনো আউটপুট প্রিফিক্স থাকে না, কিন্তু কী-টিতে সেই আইডিটি থাকে যা প্রিহ্যাশ ভ্যালুর জন্য প্রয়োজন।
NO_PREFIX (raw) ভ্যারিয়েন্ট ব্যবহার করা কীগুলো সমর্থিত নয়, কারণ সেগুলোর কোনো কী আইডি নেই।
উদাহরণ
নিম্নলিখিত উদাহরণগুলিতে দুটি ধাপে একটি বার্তা স্বাক্ষর করা হয় এবং তারপরে সাধারণ ডিজিটাল স্বাক্ষর প্রিমিটিভ ব্যবহার করে প্রাপ্ত স্বাক্ষরটি যাচাই করা হয়।
পাঠযোগ্যতার জন্য এগুলোকে একটি ব্লক হিসেবে দেখানো হয়। বাস্তব প্রয়োগে এই দুটি ধাপ ভিন্ন ভিন্ন স্থানে চলে; ধাপে ধাপে নির্দেশনার জন্য "আমি একজন রিমোট সাইনারের মাধ্যমে ডেটা স্বাক্ষর করতে চাই" দেখুন।
সি++
#include "tink/keyset_handle.h" #include "tink/public_key_verify.h" #include "tink/signature/config_2026.h" #include "tink/signature/prehash.h" #include "tink/signature/sign_prehash.h" using ::crypto::tink::ConfigSignature2026; using ::crypto::tink::Prehash; using ::crypto::tink::PublicKeyVerify; using ::crypto::tink::SignPrehash; // 1. Wherever the message is: compute the prehash value. This needs only // the public keyset. absl::StatusOr<std::unique_ptr<Prehash>> prehasher = public_handle.GetPrimitive<Prehash>(ConfigSignature2026()); if (!prehasher.ok()) return prehasher.status(); absl::StatusOr<std::string> prehash = (*prehasher)->Compute(message); if (!prehash.ok()) return prehash.status(); // 2. Wherever the private key is: turn the prehash value into a signature. absl::StatusOr<std::unique_ptr<SignPrehash>> signer = private_handle.GetPrimitive<SignPrehash>(ConfigSignature2026()); if (!signer.ok()) return signer.status(); absl::StatusOr<std::string> signature = (*signer)->Sign(*prehash); if (!signature.ok()) return signature.status(); // 3. Anywhere: verify the signature over the original message. absl::StatusOr<std::unique_ptr<PublicKeyVerify>> verifier = public_handle.GetPrimitive<PublicKeyVerify>(ConfigSignature2026()); if (!verifier.ok()) return verifier.status(); absl::Status verified = (*verifier)->Verify(*signature, message);
যান
import ( "github.com/tink-crypto/tink-go/v2/signature" "github.com/tink-crypto/tink-go/v2/signprehash" ) // 1. Wherever the message is: compute the prehash value. This needs only // the public keyset. prehasher, err := signprehash.NewPrehash(publicHandle) if err != nil { return err } prehash, err := prehasher.ComputePrehash(message) if err != nil { return err } // 2. Wherever the private key is: turn the prehash value into a signature. signer, err := signprehash.NewPrehashSigner(privateHandle) if err != nil { return err } sig, err := signer.SignPrehash(prehash) if err != nil { return err } // 3. Anywhere: verify the signature over the original message. verifier, err := signature.NewVerifier(publicHandle) if err != nil { return err } if err := verifier.Verify(sig, message); err != nil { return err }
পাইথন
from tink import signature # Needed for PublicKeyVerify in step 3. Due to the internal structure of # Tink Python, Prehash and SignPrehash are an exception where calling # signature.register() is not necessary; do not expect the same for other # primitives. signature.register() # 1. Wherever the message is: compute the prehash value. This needs only # the public keyset. prehasher = public_handle.primitive(signature.Prehash) prehash = prehasher.compute(message) # 2. Wherever the private key is: turn the prehash value into a signature. signer = private_handle.primitive(signature.SignPrehash) sig = signer.sign(prehash) # 3. Anywhere: verify the signature over the original message. verifier = public_handle.primitive(signature.PublicKeyVerify) verifier.verify(sig, message)
সম্পর্কিত বিষয়
- আমি একজন দূরবর্তী স্বাক্ষরকারীর মাধ্যমে ডেটা স্বাক্ষর করতে চাই — এই দুই-ধাপের কার্যপ্রবাহের একটি ধাপে ধাপে বিবরণ।
- ডিজিটাল স্বাক্ষর — এক ধাপেই স্বাক্ষর ও যাচাই করা যায়, এবং স্বাক্ষরকারী বার্তাটি দেখতে পারেন।
- ভাষা অনুযায়ী সমর্থিত প্রিমিটিভ কী-এর প্রকারভেদ
- টিঙ্ক ওয়্যার ফরম্যাট — একটি প্রিহ্যাশ মানের বাইট-স্তরের বিন্যাস, যা টিঙ্ককে অন্য কোনো ভাষায় পোর্ট করার জন্য ব্যবহৃত হয়।
Prehash এবং SignPrehash প্রিমিটিভগুলো একটি ডিজিটাল স্বাক্ষরের গণনাকে দুটি ধাপে বিভক্ত করে:
- প্রিহ্যাশের জন্য শুধুমাত্র পাবলিক কী প্রয়োজন। এটি যেকোনো দৈর্ঘ্যের একটি মেসেজকে একটি সংক্ষিপ্ত, নির্দিষ্ট আকারের প্রিহ্যাশ ভ্যালুতে রূপান্তরিত করে।
- SignPrahash-এর জন্য প্রাইভেট কী প্রয়োজন। এটি একটি প্রিহ্যাশ ভ্যালুকে সিগনেচারে রূপান্তরিত করে।
যে সিগনেচারটি তৈরি হয়, তা মূল মেসেজের উপর করা একটি সাধারণ সিগনেচার। আপনি সাধারণ ডিজিটাল সিগনেচার PublicKeyVerify প্রিমিটিভ ব্যবহার করে এটি ভেরিফাই করেন, এবং ভেরিফায়ারদের এটা জানার বা এতে মাথা ঘামানোর প্রয়োজন নেই যে সিগনেচারটি দুটি ধাপে তৈরি করা হয়েছে।
প্রিহ্যাশ ভ্যালুটিকে অপাক বাইট হিসেবে বিবেচনা করুন। এর একটি নির্দিষ্ট আকার আছে এবং এটি যে কী-এর জন্য গণনা করা হয়েছে তার আইডি বহন করে, কিন্তু এর লেআউটটি টিঙ্ক-এর ওয়্যার ফরম্যাটের একটি অংশ, এবং আপনার নিজে থেকে এটি পার্স বা তৈরি করা উচিত নয়। আপনি যদি টিঙ্ক পোর্ট করেন বা বাইট-স্তরের বিশদ বিবরণের প্রয়োজন হয়, তবে টিঙ্ক ওয়্যার ফরম্যাট দেখুন।
এই জোড়া প্রিমিটিভ কখন ব্যবহার করবেন:
- সাইনিং কী-টি অন্য কোথাও থাকে , যেমন একটি HSM-এ, একটি KMS-এ, বা একটি RPC বাউন্ডারির পিছনে, এবং আপনি সেই বাউন্ডারির ওপার থেকে সম্পূর্ণ মেসেজটি পাঠাতে চাইবেন না।
- বার্তাটি বড় , এবং দূরবর্তী স্বাক্ষরকারী অনুরোধের আকারের উপর একটি সীমা আরোপ করে।
যদি এর কোনোটিই প্রযোজ্য না হয়, তাহলে এর পরিবর্তে সাধারণ ডিজিটাল সিগনেচার প্রিমিটিভটি ব্যবহার করুন: এটি আরও সরল এবং এর অপব্যবহার করাও কঠিন।
কীসেট
এই দুটি প্রিমিটিভ ভিন্নভাবে কী নির্বাচন করে, ঠিক যেমনভাবে ডিজিটাল সিগনেচার প্রিমিটিভের জন্য সাইনিং এবং ভেরিফিকেশন কাজ করে থাকে:
-
Prehash.Computeসর্বদা পাবলিক কীসেটের প্রাইমারি কী ব্যবহার করে এবং প্রিহ্যাশ ভ্যালুতে সেই কী-এর আইডি রেকর্ড করে। কোন কী দিয়ে সিগনেচার তৈরি করা হবে, তা এই পক্ষই নির্বাচন করে । -
SignPrehash.Signপ্রিহ্যাশ ভ্যালু থেকে কী আইডিটি পড়ে নেয় এবং প্রাইভেট কীসেটের সাথে মিলে যাওয়া সক্রিয় কী দিয়ে সাইন করে। এটি সেই অংশ যা অন্য কারো করা পছন্দকে অনুসরণ করে । যদি কীসেটের কোনো সক্রিয় কী-তে সেই আইডিটি না থাকে, তাহলে কলটি ব্যর্থ হয়।
একটি SignPreahash কীসেটের প্রতিটি কী-এর একটি আইডি থাকা আবশ্যক, অন্যথায় প্রিমিটিভটি তৈরি করা ব্যর্থ হয়।
ন্যূনতম নিরাপত্তা গ্যারান্টি
- ফলস্বরূপ প্রাপ্ত স্বাক্ষরটির বৈশিষ্ট্যগুলো, একই কী টাইপ ব্যবহার করে ডিজিটাল সিগনেচার প্রিমিটিভ দ্বারা তৈরি স্বাক্ষরের বৈশিষ্ট্যের অনুরূপ হয়।
- Tink প্রিহ্যাশ ভ্যালুর শুরুতে ৫ বাইট যোগ করে, যার মধ্যে একটি বিশেষ সংরক্ষিত ভ্যালু এবং যে কী-এর জন্য এটি গণনা করা হয়েছে তার আইডি থাকে।
SignPrehashশুধুমাত্র সেই কী দিয়েই ভ্যালুটিকে সাইন করে। ভ্যালুটি ক্রিপ্টোগ্রাফিকভাবে সেই কী-এর সাথে আবদ্ধ থাকবে কিনা তা অ্যালগরিদমের উপর নির্ভর করে; External Mu ML-DSA-এর ক্ষেত্রে এটি আবদ্ধ থাকে, Tink wire format দেখুন। - বার্তার দৈর্ঘ্য ইচ্ছামতো হতে পারে।
যেসব বিষয়ে সতর্ক থাকতে হবে
- স্বাক্ষরকারী যা স্বাক্ষর করে তা পরিদর্শন করতে পারে না। যে কেউ
SignPrehashকল করতে পারলেই যেকোনো বার্তা স্বাক্ষর করিয়ে নিতে পারে, এবং স্বাক্ষরকারীর কাছে বার্তার বিষয়বস্তুর উপর কোনো নীতি প্রয়োগ করার উপায় থাকে না।SignPrehashএর অ্যাক্সেসকে ঠিক সেভাবেই সুরক্ষিত করুন, যেভাবে আপনিPublicKeySignএর অ্যাক্সেসকে সুরক্ষিত করেন। - স্থানান্তরের সময় প্রিহ্যাশ মানটি সুরক্ষিত রাখুন। এটি গোপনীয় নয়, কিন্তু একজন আক্রমণকারী যিনি স্থানান্তরের সময় এটি পরিবর্তন করতে পারেন, তিনি নিয়ন্ত্রণ করেন যে কী স্বাক্ষরিত হবে।
একটি কী-টাইপ বেছে নিন
RFC 9881- এ বর্ণিত এক্সটার্নাল মু মোডে থাকা ML-DSA-ই একমাত্র অ্যালগরিদম যা Tink, Prehash এবং SignPrehash-এর জন্য সমর্থন করে। এই প্রিমিটিভগুলোর সাথে আপনার একটি স্ট্যান্ডার্ড ML-DSA কী ব্যবহার করা উচিত।
অধিকাংশ ব্যবহারের ক্ষেত্রে আমরা ML_DSA_65 সুপারিশ করি।
কী-টির একটি আইডি থাকা আবশ্যক, কারণ প্রতিটি প্রিহ্যাশ ভ্যালু একটি প্রিফিক্স দিয়ে শুরু হয়, যেটিতে সেই কী-টির আইডি থাকে যার জন্য এটি গণনা করা হয়েছে। নিম্নলিখিত ভ্যারিয়েন্টগুলো গ্রহণযোগ্য:
-
TINK-- ফলস্বরূপ সিগনেচারটি Tink-এর সাধারণ ৫-বাইট আউটপুট প্রিফিক্স দিয়ে শুরু হয়। -
NO_PREFIX_WITH_PREHASH_ID-- এর ফলে প্রাপ্ত সিগনেচারে কোনো আউটপুট প্রিফিক্স থাকে না, কিন্তু কী-টিতে সেই আইডিটি থাকে যা প্রিহ্যাশ ভ্যালুর জন্য প্রয়োজন।
NO_PREFIX (raw) ভ্যারিয়েন্ট ব্যবহার করা কীগুলো সমর্থিত নয়, কারণ সেগুলোর কোনো কী আইডি নেই।
উদাহরণ
নিম্নলিখিত উদাহরণগুলিতে দুটি ধাপে একটি বার্তা স্বাক্ষর করা হয় এবং তারপরে সাধারণ ডিজিটাল স্বাক্ষর প্রিমিটিভ ব্যবহার করে প্রাপ্ত স্বাক্ষরটি যাচাই করা হয়।
পাঠযোগ্যতার জন্য এগুলোকে একটি ব্লক হিসেবে দেখানো হয়। বাস্তব প্রয়োগে এই দুটি ধাপ ভিন্ন ভিন্ন স্থানে চলে; ধাপে ধাপে নির্দেশনার জন্য "আমি একজন রিমোট সাইনারের মাধ্যমে ডেটা স্বাক্ষর করতে চাই" দেখুন।
সি++
#include "tink/keyset_handle.h" #include "tink/public_key_verify.h" #include "tink/signature/config_2026.h" #include "tink/signature/prehash.h" #include "tink/signature/sign_prehash.h" using ::crypto::tink::ConfigSignature2026; using ::crypto::tink::Prehash; using ::crypto::tink::PublicKeyVerify; using ::crypto::tink::SignPrehash; // 1. Wherever the message is: compute the prehash value. This needs only // the public keyset. absl::StatusOr<std::unique_ptr<Prehash>> prehasher = public_handle.GetPrimitive<Prehash>(ConfigSignature2026()); if (!prehasher.ok()) return prehasher.status(); absl::StatusOr<std::string> prehash = (*prehasher)->Compute(message); if (!prehash.ok()) return prehash.status(); // 2. Wherever the private key is: turn the prehash value into a signature. absl::StatusOr<std::unique_ptr<SignPrehash>> signer = private_handle.GetPrimitive<SignPrehash>(ConfigSignature2026()); if (!signer.ok()) return signer.status(); absl::StatusOr<std::string> signature = (*signer)->Sign(*prehash); if (!signature.ok()) return signature.status(); // 3. Anywhere: verify the signature over the original message. absl::StatusOr<std::unique_ptr<PublicKeyVerify>> verifier = public_handle.GetPrimitive<PublicKeyVerify>(ConfigSignature2026()); if (!verifier.ok()) return verifier.status(); absl::Status verified = (*verifier)->Verify(*signature, message);
যান
import ( "github.com/tink-crypto/tink-go/v2/signature" "github.com/tink-crypto/tink-go/v2/signprehash" ) // 1. Wherever the message is: compute the prehash value. This needs only // the public keyset. prehasher, err := signprehash.NewPrehash(publicHandle) if err != nil { return err } prehash, err := prehasher.ComputePrehash(message) if err != nil { return err } // 2. Wherever the private key is: turn the prehash value into a signature. signer, err := signprehash.NewPrehashSigner(privateHandle) if err != nil { return err } sig, err := signer.SignPrehash(prehash) if err != nil { return err } // 3. Anywhere: verify the signature over the original message. verifier, err := signature.NewVerifier(publicHandle) if err != nil { return err } if err := verifier.Verify(sig, message); err != nil { return err }
পাইথন
from tink import signature # Needed for PublicKeyVerify in step 3. Due to the internal structure of # Tink Python, Prehash and SignPrehash are an exception where calling # signature.register() is not necessary; do not expect the same for other # primitives. signature.register() # 1. Wherever the message is: compute the prehash value. This needs only # the public keyset. prehasher = public_handle.primitive(signature.Prehash) prehash = prehasher.compute(message) # 2. Wherever the private key is: turn the prehash value into a signature. signer = private_handle.primitive(signature.SignPrehash) sig = signer.sign(prehash) # 3. Anywhere: verify the signature over the original message. verifier = public_handle.primitive(signature.PublicKeyVerify) verifier.verify(sig, message)
সম্পর্কিত বিষয়
- আমি একজন দূরবর্তী স্বাক্ষরকারীর মাধ্যমে ডেটা স্বাক্ষর করতে চাই — এই দুই-ধাপের কার্যপ্রবাহের একটি ধাপে ধাপে বিবরণ।
- ডিজিটাল স্বাক্ষর — এক ধাপেই স্বাক্ষর ও যাচাই করা যায়, এবং স্বাক্ষরকারী বার্তাটি দেখতে পারেন।
- ভাষা অনুযায়ী সমর্থিত প্রিমিটিভ কী-এর প্রকারভেদ
- টিঙ্ক ওয়্যার ফরম্যাট — একটি প্রিহ্যাশ মানের বাইট-স্তরের বিন্যাস, যা টিঙ্ককে অন্য কোনো ভাষায় পোর্ট করার জন্য ব্যবহৃত হয়।