مترجمة عن المقالة الأصلية باللغة الإنجليزية. اقرأها بالإنجليزية

أنظمة الهوية اليوم تفرض قدرًا هائلًا من الثقة في الشركات لتخزين بياناتك بأمان. فعدة مزوّدين لخدمات KYC يحتفظون ببياناتك إلى أجل غير مسمّى. وكل تطبيق يحصل على تفاصيلك الكاملة حتى عندما لا يحتاج إلا إلى معرفة أن عمرك يتجاوز 18+ عامًا، وهذا قدر مفرط من المعلومات يُشارَك ويُترك مبعثرًا في كل مكان.
تعالج الهوية ذاتية السيادة SSI هذه المشكلة بمنحك التحكم في اعتماداتك، فيمكنك مشاركة ما هو ضروري فقط، وإثبات الادعاءات دون كشف البيانات. فالاعتمادات القابلة للتحقق VC تتيح لك في الأساس إثبات أنك تجاوزت 18+ عامًا دون إظهار تاريخ ميلادك الدقيق. لكن لدى SSI مشكلة - أين تخزّن المفاتيح الخاصة التي تتحكم في هويتك؟
هناك الكثير من الحلول الجوهرية لهذه المشكلة، وأحدها biometric crypto identities، وهو ليس من الحلول الشائعة، والسؤال هو: ماذا لو كانت سمتك الحيوية biometric، مثل وجهك face، هي مفتاحك الخاص private-key؟ لا عبارات استرداد seed phrases تفقدها، ولا كلمات مرور passwords تنساها، ولا مفاتيح keys تخزّنها. سمتك الحيوية biometric تولّد محفظتك wallet، التي تحمل اعتماداتك القابلة للتحقق، والتي تثبتها باستخدام ZKPs.
وهذا ممكن عبر fuzzy extractors + zero-knowledge proofs. وإليك طريقة عمله.
صُمّمت الأنظمة التشفيرية التقليدية للتعامل مع بتّات قابلة لإعادة الإنتاج. لكن القياسات الحيوية تكسر قاعدتين أساسيتين تعتمد عليهما هذه الأنظمة:
يجب أن تكون المفاتيح قابلة لإعادة الإنتاج بشكل تام - فهي تتطلب إعادة إنتاج المفتاح بدقة على مستوى البت. ويجب أن يكون مفتاحك الخاص لتوقيع المعاملات متطابقًا في كل مرة على الإطلاق. لكن القياسات الحيوية مشوّشة، وهناك الكثير من المتغيرات التي يجب مراعاتها. فمسح بصمة إصبعك اليوم لن يطابق مسح الأمس بتًّا ببت بسبب اختلافات المستشعر، وطريقة وضع الإصبع، والرطوبة، ودرجة الحرارة - والقائمة تطول وتطول. والأمر نفسه ينطبق على مسح الوجه، وأنماط القزحية، وأي قياس بيولوجي.
يجب أن تكون المفاتيح عشوائية بتوزيع منتظم - يفترض الأمان التشفيري أن مفتاحك مسحوب عشوائيًا بتوزيع منتظم من فضاء المفاتيح بأكمله. لكن البيانات الحيوية لها بنية وأنماط. فقزحيتك ليست عشوائية بتوزيع منتظم، بل لها قيود بيولوجية، وأوجه تشابه على مستوى السكان، وإنتروبيا مركّزة في سمات بعينها.
وهذا يخلق مشكلة الدجاجة والبيضة المعتادة: لا يمكنك استخدام القياسات الحيوية مباشرة كمفاتيح فهي مشوّشة جدًا، ولا يمكنك تخزينها بأمان فهي معلومات تعريف شخصية (PII) وغير قابلة للتغيير، ولا يمكنك ببساطة تجزئتها فالتشويش يكسر دوال التجزئة كما تعلم. فماذا تفعل إذن؟
والآن إلى بيت القصيد!
انظر إلى المستخلِصات الضبابية على أنها تشفير مصحّح للأخطاء مخصص للبيانات المشوّشة. وهي زوج من الخوارزميات، Gen للتوليد و Rep لإعادة الإنتاج، تفعل شيئًا مثيرًا جدًا:
- تأخذ مدخلك الحيوي المشوّش w، وتُخرج سلسلة عشوائية بتوزيع منتظم R وهي المفتاح التشفيري الفعلي وسلسلة مساعدة عامة P. وإليك حقيقة ممتعة أخرى: يمكن نشر P علنًا دون المساس بالأمان. فهي لا تكشف أي معلومة ذات معنى عن سمتك الحيوية على الإطلاق.
- تأخذ قراءة حيوية مختلفة w' وسلسلة المساعدة العامة نفسها P، وتعيد إنتاج R نفسه تمامًا ما دامت w' قريبة بما يكفي من w الأصلية. أعلم أن هذا مخيف، لكن القرب الكافي في هذه الحالة يُقاس بالمسافة في فضاء متري ما مسافة Hamming للسلاسل الثنائية، ومسافة التحرير للتسلسلات، وفرق المجموعات لمتجهات السمات.
ضمان الأمان هنا قائم على نظرية المعلومات، فحتى مع معرفة P، يكون المفتاح المستخلَص R قريبًا بمقدار من التوزيع المنتظم ما دامت لسمتك الحيوية إنتروبيا دنيا . ولا حاجة إلى أي افتراضات بشأن الصعوبة الحسابية. فالخصم الذي يملك قدرة حوسبة غير محدودة لا يزال عاجزًا عن تمييز R من مفتاح عشوائي حقيقي بأفضلية تتجاوز .
الرياضيات هنا جميلة. بالنسبة إلى مستخلِص ضبابي بالمعاملات :
Rw' عن wتستخدم البنية عنصرين أوليين يعملان معًا:
المخطط الآمن يشبه الالتزام الضبابي. فـ تُخرج مخططًا s يكشف من المعلومات ما يكفي لتصحيح الأخطاء فقط، لكنه أبعد ما يكون عن الكفاية لإعادة بناء w نفسها. ثم تستعيد قيمة w الأصلية من w' المشوّشة باستخدام المخطط.
بالنسبة إلى السلاسل الثنائية مع مسافة Hamming، تكون بنية المتلازمة (Syndrome Construction) هي الأمثل:
class SyndromeSketch:
def __init__(self, n, k, t):
self.n, self.k, self.t = n, k, t
self.syn_matrix = generate_bch_syndrome_matrix(n, k)
def sketch(self, w):
return np.dot(self.syn_matrix, w) % 2
def recover(self, w_prime, s):
s_prime = np.dot(self.syn_matrix, w_prime) % 2
error_syn = (s_prime - s) % 2
e = bch_decode(error_syn, self.t)
return (w_prime - e) % 2ما الذي يحدث هنا:
sketch() متلازمة السمة الحيوية w، وتُخرج s بطول $n-k$ بتrecover() الأخطاء في w_prime المشوّشة باستخدام المخطط s$n-k$ بتBCH الموسّعة شيفرات Bose–Chaudhuri–Hocquenghem: تخسر 64 بت، وتصحّح حتى أخطاءبعد تصحيح الأخطاء، تجزّئ السمة الحيوية المستعادة لاستخلاص مفتاح بتوزيع منتظم، على سبيل المثال
pub fn fuzzy_gen(biometric: &[u8]) -> (Vec<u8>, Vec<u8>) {
let sketch = secure_sketch(biometric);
let seed: Vec<u8> = (0..32).map(|_| rng.gen()).collect();
let key = extract_key(biometric, &seed);
let helper = [sketch, seed].concat();
(key, helper)
}
pub fn fuzzy_rep(noisy_biometric: &[u8], helper: &[u8]) -> Vec<u8> {
let (sketch, seed) = split_helper(helper);
let recovered = sketch_recover(noisy_biometric, sketch);
extract_key(&recovered, &seed)
}الدالة fuzzy_gen():
hash(biometric || seed)key, helper حيث helper = sketch, seedالدالة fuzzy_rep():
بالنسبة إلى القياسات الحيوية المعتادة:
ملاحظة: تحتوي التمثيلات الحيوية الخام على تكرار وارتباطات. فشيفرات القزحية تُظهر نسبة ~8:1 بين البتّات الخام (2048) والإنتروبيا وفق نظرية المعلومات (~249 بت). ويجب أن يحترم استخلاص المفتاح الإنتروبيا الفعلية، لا حجم التمثيل.

يضم نموذج الثقة في SSI ثلاث جهات فاعلة:
التدفق الكامل: السمة الحيوية ← المحفظة ← الاعتمادات ← براهين ZK ← هوية موثّقة

لنلقِ نظرة عليه خطوة بخطوة:
async function biometricToWallet(rawBiometric) {
const binary = await preprocessBiometric(rawBiometric);
const { key, helper } = await fuzzyExtractor.gen(binary);
const expandedKey = await hkdf(
key,
128,
'bip39-seed',
await crypto.getRandomValues(new Uint8Array(32))
);
const mnemonic = bip39.entropyToMnemonic(expandedKey);
const seed = await bip39.mnemonicToSeed(mnemonic);
const master = bip32.fromSeed(seed);
return {
btc: deriveBitcoin(master),
eth: deriveEthereum(master),
sol: deriveSolana(seed),
helper,
salt
};
}العملية:
fuzzy_gen() ← الحصول على مفتاح بطول 40-128 بت + سلسلة مساعدة عامةBIP39 ← اشتقاق بذرة محفظة HDP2WPKH، و ETH EVM، و SOL Ed25519بالنسبة إلى Solana تحديدًا، فهي تستخدم منحنى مختلفًا:
import { derivePath } from 'ed25519-hd-key';
const solSeed = derivePath("m/44'/501'/0'/0'", seed.toString('hex')).key;
const solKeypair = Keypair.fromSeed(solSeed);
const solAddress = solKeypair.publicKey.toBase58();ملاحظة: تستخدم Solana
Ed25519، لاsecp256k1. لذا استخدم في تنفيذكed25519-hd-keyلتحقيق التوافق معSLIP-0010بما يطابقPhantomوSolflare.
محفظتك لديها الآن DID، لكن لإثبات أي شيء، تحتاج إلى اعتمادات قابلة للتحقق VC. وهنا يبدأ مثلث الثقة.
يتحقق المُصدِر من مستنداتك خارج السلسلة ويصدر برهانًا موقّعًا تشفيريًا:
async function requestCredential(wallet, issuerEndpoint, claimData) {
const connectionRequest = await issuerEndpoint.createConnection(wallet.did);
const credentialOffer = await issuerEndpoint.offerCredential({
type: 'KYCCredential',
schema: 'https://schema.org/kyc-v1',
claims: {
country: claimData.country,
birthYear: claimData.birthYear,
verified: true
}
});
const signedVC = await wallet.acceptCredential(credentialOffer);
await wallet.storeCredential(signedVC);
return signedVC;
}ما الذي حدث:
VC موقّعة تشفيريًا (cryptographically) تتضمن ادعاءاتكVC توقيع DID الخاص بالمُصدِر الذي يثبت أصالتهاVCs من مُصدِرين مختلفين في التعليم والتوظيف و KYCيحدد مخطط الاعتماد ما تحتويه الـ VC:
{
"@context": "https://www.w3.org/2018/credentials/v1",
"type": ["VerifiableCredential", "KYCCredential"],
"issuer": "did:polygonid:polygon:amoy:2qH7...",
"issuanceDate": "2025-01-15T00:00:00Z",
"credentialSubject": {
"id": "did:polygonid:polygon:amoy:2qPz...",
"birthYear": 1995,
"country": "US",
"kycVerified": true
},
"proof": {
"type": "BJJSignature2021",
"issuerData": {...},
"signature": "0x..."
}
}والآن عندما يطلب منك مُتحقِّق أن تثبت أن عمرك 18+، تولّد ZKP من هذا الاعتماد.
هنا يمكنك إثبات تفاصيلك الشخصية مثل العمر، والجنسية، والشهادة الجامعية، والعنوان، وتاريخ الميلاد، وغير ذلك دون كشف هذه البيانات الحساسة.
async function proveAge(wallet, minAge) {
const credential = await wallet.getCredential('kyc');
const inputs = {
birthYear: credential.birthYear,
currentYear: 2025,
minAge: minAge,
signature: credential.signature
};
const { proof, publicSignals } = await snarkjs.groth16.fullProve(
inputs,
"ageCheck.wasm",
"ageCheck.zkey"
);
return { proof, publicSignals };
}ما الذي يُثبَت:
minAge عامًادائرة Circom:
template AgeCheck() {
signal input birthYear;
signal input currentYear;
signal input minAge;
signal age <== currentYear - birthYear;
component check = GreaterEqThan(16);
check.in[0] <== age;
check.in[1] <== minAge;
signal output isValid;
isValid <== check.out;
}التحقق على السلسلة - Solidity:
contract IdentityGate {
mapping(address => mapping(uint256 => bool)) public verified;
function submitProof(
uint256 requestId,
uint[2] calldata pA,
uint[2][2] calldata pB,
uint[2] calldata pC,
uint[3] calldata pubSignals
) external {
require(zkpVerifier.verifyProof(pA, pB, pC, pubSignals), "Invalid proof");
require(pubSignals[2] >= minAge, "Age requirement not met");
verified[msg.sender][requestId] = true;
_grantAccess(msg.sender);
}
}العقد:
إذن، من هذا التدفق يمكنك أن ترى كيف أصبحت سمتك الحيوية:
DID مرتبط بسمتك الحيويةVC من مُصدِرين موثوقينZKP لا تكشف شيئًا عنكوهذه ليست أنظمة منفصلة متعددة - بل هي تدفق واحد موحّد. يحدث توليد المحفظة مرة واحدة أثناء التسجيل. ويمكن استخدام تدفق ZKP كلما احتجت إلى التحقق من الهوية. فكّر في الأمر هكذا: يمكنك استخدام محفظتك الحيوية تمامًا كأي محفظة عملات مشفرة أخرى للمعاملات العادية. لكن عندما يحتاج dApp إلى KYC أو إلى أي نوع من التحقق القائم على PII مثل حالات استخدام Polygon ID، تتدخل طبقة ZKP لإثبات الاعتمادات دون كشف بياناتك.
يمكن لكل وكيل ذكاء اصطناعي أن يمتلك DID مشتقًا من سمة حيوية. تخيّل وكيل تداول بالذكاء الاصطناعي يمتلك محفظته الخاصة واعتماداته الموثّقة:
class TradingAgent {
constructor(agentFingerprint) {
this.wallet = await biometricToWallet(agentFingerprint);
this.did = await createDID(this.wallet);
}
async trade(dex, params) {
const proof = await this.proveReputation();
return await dex.trade(params, proof);
}
}الوكيل:
biometric تجزئة الشبكة العصبيةZKPتبني SingularityNET هذا بالضبط، وهو سجل ثقة لوكلاء الذكاء الاصطناعي يثبت فيه الوكلاء أصالتهم وسلامتهم وحالة تدقيقهم باستخدام اعتمادات قابلة للتحقق. ويتيح تدفق biometric-wallet-ZKP للوكلاء العمل بمفردهم مع الحفاظ على المساءلة.
يحتاج بروتوكول DeFi إلى KYC لكنه لا يريد تخزين بيانات المستخدمين مسؤولية تنظيمية + مصيدة مغرية للمخترقين:
contract DeFiProtocol {
modifier onlyKYCVerified() {
require(identityGate.verified(msg.sender, KYC_ID), "KYC required");
_;
}
function borrowUndercollateralized(uint256 amount) external onlyKYCVerified {
_issueLoan(msg.sender, amount);
}
}لا يرى البروتوكول أبدًا جواز سفرك أو اسمك أو عنوانك. تحقّق الامتثال، وحُفظت الخصوصية.
النمط نفسه ينطبق على:
async function login(website) {
const { key } = await fuzzyExtractor.rep(biometric, helper);
const siteKey = deriveKey(key, website.domain);
const signature = sign(challenge, siteKey);
await website.verify(signature);
}يحصل كل موقع على مفتاح مشتق فريد. لا كلمة مرور تُرسَل، ولا بيانات اعتماد يمكن اصطيادها.
سمتك الحيوية هي التي تفوّض المعاملة:
async function pay(merchant, amount) {
const wallet = await biometricToWallet(scan);
if (amount > 1000) {
await merchant.verifyProof(generateKYCProof(wallet));
}
await wallet.sendTransaction({ to: merchant.address, value: amount });
}تطبّق BMONI + BKey هذا حاليًا، إذ تُشتق محافظك كلها بالكامل من سمتك الحيوية "وجهك"، وتُجهَّز المحافظ عبر سلاسل EVM ورموز محددة، وكل ذلك عبر وجهك!
contract AML {
bytes32 public scamMerkleRoot;
function checkClean(address wallet, bytes32[] calldata proof) public view returns (bool) {
bytes32 hash = keccak256(abi.encodePacked(wallet));
return !MerkleProof.verify(proof, scamMerkleRoot, hash);
}
}تستعلم الـ dApps قبل السماح بالوصول. يُحظر المحتالون المعروفون على مستوى الشبكة بأكملها، ويُرصد أيضًا من لديهم سجل من النشاط الغريب، بينما يتلقى المُدمِجون إشعارًا بالنشاط المشبوه السابق.
يحتاج البناء باستخدام الهويات الحيوية إلى بنية تحتية. وتوفر المنظومة ثلاثة مكوّنات أساسية:
تشغّل المؤسسات عُقد مُصدِر مستضافة ذاتيًا لإصدار الاعتمادات:
docker-compose up -d
make import-private-key-to-kms private_key=<eth-key>
# access the ui at localhost:8088
# access the api at localhost:3001الميزات:
DID للمُصدِرschemas الاعتماداتVCs وإلغاؤهامثال على الـ API:
const issuerAPI = new IssuerNode({
url: 'https://issuer.example.com',
auth: { user: 'admin', password: 'secure' }
});
await issuerAPI.createIdentity({
blockchain: 'polygon',
network: 'amoy',
method: 'polygonid'
});
await issuerAPI.issueCredential({
did: 'did:polygonid:...',
schema: 'KYCCredential',
claims: { ageOver: 18 }
});منظومة الأدوات
tools.privado.id/buildertools.privado.id/query-builderschemas المجتمعissuers الاعتمادات1: تباين القياسات الحيوية
تتباين بصمة إصبعك بنسبة 10-15% بين عمليات المسح. الحل: شيفرات BCH هي الأمثل لتصحيح الأخطاء على مستوى البت. بالنسبة إلى شيفرة قزحية بطول 2048 بت تحتوي على ~249 بت من الإنتروبيا الفعلية مع نسبة أخطاء 10% (~205 أخطاء في البتّات):
تمييز جوهري: الـ 2048 بت هي تمثيل شيفرة القزحية الخام مخرجات خوارزمية Daugman. أما الإنتروبيا الفعلية وفق نظرية المعلومات فلا تتجاوز ~249 بت بسبب الارتباطات البيولوجية والتكرار بنسبة ~8:1.
2: تقادم القالب
المشكلة: يتغير وجهك مع مرور الوقت التقدم في العمر، والوزن، وشعر الوجه، وغير ذلك
الحل: إعادة تسجيل دورية مع ترحيل المفتاح:
async function migrate(oldBio, newBio) {
const oldWallet = await recover(oldBio);
const { newWallet, newHelper } = await enroll(newBio);
await oldWallet.transferAll(newWallet.address);
await storage.update(newHelper);
}أعِد التسجيل كل 2-3 سنوات للوجه، وكل 5 سنوات للقزحية، وسنويًا للصوت، وهكذا.
3: كشف الحيوية (Liveness Detection)
المشكلة: لا ينبغي أن يتمكن المهاجمون الذين يملكون صورتك من الوصول إلى محفظتك.
الحل: فحوصات الحيوية أثناء التقاط السمة الحيوية:
const checks = await Promise.all([
depthSensor.measure(),
motionDetector.verify(['blink', 'nod']),
thermalCamera.capture(),
videoAnalyzer.checkTemporal()
]);يفعل Orb الخاص بـ WorldCoin ذلك مع مسح القزحية: 25+ فحصًا للحيوية، وتصوير ثلاثي الأبعاد، وكاميرات بالأشعة تحت الحمراء + RGB. ويعمل بشكل مذهل - معدل القبول الخاطئ .
4: خصوصية سلسلة المساعدة
هل تسرّب P التي شرحناها سابقًا معلومات حيوية؟ لا. وفق النظرية Dodis et al.، يعرف المهاجم على الأكثر بت طول المخطط، ويبقى المفتاح R عشوائيًا إحصائيًا. وبالنسبة إلى قزحيتنا: يعرف 408 بت، وتبقى 392 بت من الإنتروبيا.
القطع موجودة بالفعل:
CompFE (MIT)، وتعمل على الأجهزة المحمولةما الذي ينقص؟ التكاملات...
إليك كيف يبدو استخدام هذا النظام فعليًا في بيئة الإنتاج
async function enrollUser() {
const bio = await captureLive();
const { key, helper } = await fuzzyExtractor.gen(bio);
const salt = await crypto.getRandomValues(new Uint8Array(32));
const expandedKey = await hkdf('sha256', key, salt, 'bip39-seed', 128/8);
const wallet = await deriveWallet(expandedKey);
const did = await createDID(wallet.eth);
const kycCred = await requestKYC(did, { passport, selfie });
await storage.save({ helper, salt, did, credentials: [kycCred] });
return { wallet, did };
}
async function accessDApp(dappURL) {
const bio = await captureLive();
const { helper, salt } = await storage.getHelperData();
const key = await fuzzyExtractor.rep(bio, helper);
const expandedKey = await hkdf('sha256', key, salt, 'bip39-seed', 128/8);
const wallet = await deriveWallet(expandedKey);
const proof = await generateProof(wallet, dappURL.request);
await submitProof(wallet, proof, dappURL.verifier);
await dappURL.grantAccess(wallet.address);
}
async function sendPayment(recipient, amount) {
const bio = await captureLive();
const { helper, salt } = await storage.getHelperData();
const key = await fuzzyExtractor.rep(bio, helper);
const expandedKey = await hkdf('sha256', key, salt, 'bip39-seed', 128/8);
const wallet = await deriveWallet(expandedKey);
await wallet.send({ to: recipient, value: amount });
}يتعايش تدفق المحفظة العادي مع تدفق الهوية. ولا يظهر ZKP إلا عند الحاجة إلى التحقق، سواء من أجل KYC أو أي تحقق قائم على PII مثل العمر، والجنسية، والشهادة الجامعية، والعنوان، وتاريخ الميلاد، وغير ذلك.
سمتك الحيوية هي مفتاحك، ومحفظتك هي هويتك عبر جميع السلاسل المدعومة، ولن تضطر أبدًا إلى القلق من فقدان عبارة الاسترداد أو المفاتيح الخاصة، فكل شيء مرتبط بسماتك الجسدية، وفي تنفيذ BMoni هي وجهك!
احصل على أحدث المقالات في بريدك الوارد.