Ders 09 / 12
Köken Bilgisi
Yapının nerede ve nasıl üretildiğini anlatan belge alan alan kurulur ve tek bir sayıya indirgenir: on dört alanın kaçı bağımsız olarak doğrulanabiliyor, kaçı yalnız beyan olarak kalıyor, yeniden üretim kaç alanı kanıta çeviriyor ve doğrulama eşiği yükseldikçe hattan kaç saniye gidiyor.
İçindekiler
Önceki ders imzanın kapsadığı alan ile doğrulayıcının sınayabildiği alanı ayırdı: beyan dokuz alana çıktığında imza dokuzunu da kapsıyordu, ama doğrulayıcı yalnız birini yeniden hesaplayabiliyordu. Kalan sekiz alan imzalanmış olarak geçiyordu ve imzalı olmak onları doğru yapmıyordu.
Bu ders o sekiz alanın yerine geçen belgeyi kurar: yapının nerede ve nasıl üretildiğini anlatan köken bilgisi. Ölçü tek bir sayıdır — belgenin kaç alanı bağımsız olarak doğrulanabiliyor, kaçı yalnız beyan olarak kalıyor. Bir alan, doğrulayanın kendi elde edebildiği bir nesneden yeniden hesaplanabiliyorsa kanıttır; hesaplanamıyorsa beyandır ve doğruluğu onu yazana güvenmeye kalır.
TZ11. Köken belgesi dört öbekte on dört alandır: hangi kaynak, hangi işlem, hangi ortam, hangi
girdi. Belge ve nesneler node ile modellenir. TZ12. Doğrulayıcının bağımsız elde edebildiği
nesne kümesi dörttür: kaynak ağacı, yapı tanımı dosyası, bağımlılık kilit dosyası ve yapı
çıktısının baytları.
Belgenin On Dört Alanı
// olcum-agi/koken.mjs — koken belgesi alan alan kurulur: kaci bagimsiz dogrulanabiliyor import { createHash } from "node:crypto"; const ozet = (b) => createHash("sha256").update(b).digest("hex").slice(0, 12); // Kurgu bagimsiz nesneler: dogrulayici bunlari kendi elde edebilir ve yeniden ozetleyebilir. const KAYNAK = Buffer.from(["ana.js", "olcum.js", "ayar.json"] .map((y) => `${y}\n// kurgu abone portali\n`).join("")); const YAPI_TANIMI = Buffer.from("adim: derle, sina, paketle, imzala\n"); const KILIT = Buffer.from(Array.from({ length: 73 }, (_, i) => `bilesen-${i}@2.0`).join("\n")); const CIKTI = Buffer.concat([Buffer.from("abone-portali\n"), Buffer.alloc(16384, "u")]); const ELDEKI = { kaynak: KAYNAK, "yapi-tanimi": YAPI_TANIMI, kilit: KILIT, cikti: CIKTI }; // Koken belgesi: dort obek, on dort alan. `yazilan` belgeye konan deger. const BELGE = [ ["kaynak", "depo", "abone-portali", false], ["kaynak", "isleme", ozet(KAYNAK), true], ["kaynak", "dal", "ana", false], ["islem", "yapi-tanimi", ozet(YAPI_TANIMI), true], ["islem", "adim-listesi", "derle, sina, paketle, imzala", false], ["islem", "cagri-parametresi", "hedef=uretim", false], ["ortam", "calistirici-turu", "yalitilmis-kap", false], ["ortam", "temel-imaj", "7ad3e1c95006", false], ["ortam", "yalitim-duzeyi", "is basina yeni calistirici", false], ["ortam", "ag-erisimi", "kapali", false], ["girdi", "kilit", ozet(KILIT), true], ["girdi", "ortam-degiskeni-adlari", "HEDEF, SURUM", false], ["girdi", "onbellek-anahtari", "b41c-2", false], ["cikti", "cikti", ozet(CIKTI), true], ]; // Bir alan ancak elde edilebilir bir nesneden yeniden hesaplanabiliyorsa kanittir. const S = [8, 24, 29, 0]; const satir = (s) => console.log(s.map((v, i) => String(v).padEnd(S[i])).join("")); satir(["obek", "alan", "dogrulama yolu", "tur"]); let kanit = 0; for (const [obek, alan, yazilan, hesaplanir] of BELGE) { if (hesaplanir) kanit++; satir([obek, alan, hesaplanir ? "nesne yeniden ozetlenir" : "karsilastirilacak nesne yok", hesaplanir ? "kanit" : "beyan"]); } console.log(""); console.log(`belge ${BELGE.length} alan: ${kanit} kanit, ${BELGE.length - kanit} beyan`); // Bes alana kasten yanlis deger yazilir; dogrulayici elindeki nesnelerle sinar. const YANLIS = { isleme: "0000deadbeef", "yapi-tanimi": "111122223333", "temel-imaj": "999988887777", "yalitim-duzeyi": "paylasilan calistirici", cikti: "aaaabbbbcccc" }; const anahtar = { isleme: "kaynak", "yapi-tanimi": "yapi-tanimi", kilit: "kilit", cikti: "cikti" }; let yakalanan = 0; for (const [, alan, , hesaplanir] of BELGE) { if (!(alan in YANLIS)) continue; if (hesaplanir && ozet(ELDEKI[anahtar[alan]]) !== YANLIS[alan]) yakalanan++; } console.log(`kasten yanlis yazilan ${Object.keys(YANLIS).length} alanin ${yakalanan} tanesi ` + `yakalandi, ${Object.keys(YANLIS).length - yakalanan} tanesi beyan oldugu icin sinanmadi`);
obek alan dogrulama yolu tur kaynak depo karsilastirilacak nesne yok beyan kaynak isleme nesne yeniden ozetlenir kanit kaynak dal karsilastirilacak nesne yok beyan islem yapi-tanimi nesne yeniden ozetlenir kanit islem adim-listesi karsilastirilacak nesne yok beyan islem cagri-parametresi karsilastirilacak nesne yok beyan ortam calistirici-turu karsilastirilacak nesne yok beyan ortam temel-imaj karsilastirilacak nesne yok beyan ortam yalitim-duzeyi karsilastirilacak nesne yok beyan ortam ag-erisimi karsilastirilacak nesne yok beyan girdi kilit nesne yeniden ozetlenir kanit girdi ortam-degiskeni-adlari karsilastirilacak nesne yok beyan girdi onbellek-anahtari karsilastirilacak nesne yok beyan cikti cikti nesne yeniden ozetlenir kanit belge 14 alan: 4 kanit, 10 beyan kasten yanlis yazilan 5 alanin 3 tanesi yakalandi, 2 tanesi beyan oldugu icin sinanmadi
Belge on dört alan taşır ve dördü kanıttır. Dördünün ortak özelliği şudur: hepsi bir nesnenin özetidir ve o nesne doğrulayanın elinde vardır. İşleme özeti kaynak ağacından, yapı tanımı özeti depodaki dosyadan, kilit özeti bağımlılık kilit dosyasından, çıktı özeti yapı çıktısının baytlarından yeniden hesaplanır. Belge yanlış yazsa bile bu dört alanda yalan tutmaz.
Kalan on alan beyandır ve ilginç olan, aralarında hiç önemsiz bir alan bulunmamasıdır. Yalıtım düzeyi, ağ erişimi, çalıştırıcı türü ve temel imaj — dördü de yapının güvenilirliğine dair en çok şey söyleyen alanlardır. Hiçbiri sınanamaz, çünkü hiçbirinin karşılığı doğrulayanın elde edebileceği bir nesne değildir. “Ağ erişimi kapalıydı” cümlesi yapıyı koşturan tarafın kendi hakkında verdiği bir ifadedir.
Son satır bu ayrımı sayıya çevirir: beş alana kasten yanlış değer yazıldığında üçü yakalanır, ikisi sınanmaz. Yakalanmayan ikisi temel imaj ve yalıtım düzeyidir. Belgede “iş başına yeni çalıştırıcı” yazar, gerçekte paylaşılan çalıştırıcı kullanılmıştır ve hiçbir doğrulama bunu görmez. Bir köken belgesinin değeri alan sayısıyla değil, kanıt olan alan sayısıyla ölçülür.
Yeniden Üretim Neyi Kanıta Çevirir
On beyan alanının bir bölümü aslında çıktıya girer: adım listesi, çağrı parametresi ve temel imaj farklı olsaydı çıktı da farklı olurdu. Bu, sınanabilirlik için bir kaldıraç sunar — aynı bildirilen girdilerle yapı yeniden koşturulur ve çıktı aynı çıkarsa bildirim doğrulanmış olur.
TZ13. Yapı işlevi kurgudur ve bildirilen girdilerden çıktı üretir. On iki yapının üçünde
bildirilmemiş bir girdi çıktıya girer, birinde çıktı sonradan değiştirilmiştir; tohum 410277
görünürdür.
// olcum-agi/yeniden-uretim.mjs — yeniden uretim hangi alani kanita cevirir import { createHash } from "node:crypto"; const ozet = (b) => createHash("sha256").update(b).digest("hex").slice(0, 12); // Kurgu yapi islevi: bildirilen girdilerden cikti uretir. Gizli girdi varsa ciktiya o da girer. const yap = (g) => Buffer.from([g.kaynak, g.kilit, g.adimlar, g.parametre, g.temelImaj, g.gizli ?? ""].join("|")); const uretec = (tohum) => () => (tohum = (tohum * 1103515245 + 12345) % 2147483648) / 2147483648; const r = uretec(410277); // tohum gorunur // On iki kurgu yapi. Uc tanesinde bildirilmemis girdi var, birinde cikti sonradan degistirildi. const GIZLI = [3, 7, 11], DEGISTIRILEN = 9; const YAPI = Array.from({ length: 12 }, (_, i) => { const no = i + 1; const girdi = { kaynak: `kaynak-${no}`, kilit: `kilit-${no}`, adimlar: "derle,sina,paketle", parametre: "hedef=uretim", temelImaj: no % 2 ? "temel-a" : "temel-b" }; const gercek = yap(GIZLI.includes(no) ? { ...girdi, gizli: `kosum-${Math.floor(r() * 900)}` } : girdi); const beyanEdilen = no === DEGISTIRILEN ? ozet(Buffer.from("degistirilmis")) : ozet(gercek); return { no, girdi, beyanEdilen, gizliVar: GIZLI.includes(no) }; }); const S = [7, 16, 18, 12, 0]; const satir = (s) => console.log(s.map((v, i) => String(v).padEnd(S[i])).join("")); satir(["yapi", "beyan edilen", "yeniden uretilen", "eslesme", "sebep"]); let eslesen = 0, gercekBulgu = 0, yanlisIsaret = 0; for (const y of YAPI) { const tekrar = ozet(yap(y.girdi)); // yalniz BILDIRILEN girdilerle const esit = tekrar === y.beyanEdilen; if (esit) eslesen++; else if (y.gizliVar) yanlisIsaret++; else gercekBulgu++; if (y.no <= 4 || !esit) satir([y.no, y.beyanEdilen, tekrar, esit ? "evet" : "HAYIR", esit ? "-" : (y.gizliVar ? "bildirilmemis girdi" : "cikti degistirilmis")]); } console.log(""); console.log(`on iki yapinin ${eslesen}'i yeniden uretimde eslesiyor, ` + `${YAPI.length - eslesen} tanesi eslesmiyor: ${gercekBulgu} gercek, ${yanlisIsaret} yanlis isaret`); // Yeniden uretim, ciktiya giren her bildirilen girdiyi sinanabilir kilar. const CIKTIYA_GIREN = ["adim-listesi", "cagri-parametresi", "temel-imaj"]; const ONCE = 4, ALAN = 14; console.log(`kanit alani ${ONCE}/${ALAN} -> ${ONCE + CIKTIYA_GIREN.length}/${ALAN}; ` + `sinanabilir hale gelen: ${CIKTIYA_GIREN.join(", ")}`); console.log(`beyan olarak kalan ${ALAN - ONCE - CIKTIYA_GIREN.length}: ` + `depo, dal, calistirici-turu, yalitim-duzeyi, ag-erisimi, ortam-degiskeni-adlari, onbellek-anahtari`);
yapi beyan edilen yeniden uretilen eslesme sebep 1 bf07d2a43010 bf07d2a43010 evet - 2 1ddced3cf18e 1ddced3cf18e evet - 3 e8ef828e21d6 708285ad34af HAYIR bildirilmemis girdi 4 ec17c7d09dca ec17c7d09dca evet - 7 02dfd006731d 7837452fb129 HAYIR bildirilmemis girdi 9 3dfd53002487 9c98f23fe16b HAYIR cikti degistirilmis 11 1e1126a5aff6 1f5be23c2504 HAYIR bildirilmemis girdi on iki yapinin 8'i yeniden uretimde eslesiyor, 4 tanesi eslesmiyor: 1 gercek, 3 yanlis isaret kanit alani 4/14 -> 7/14; sinanabilir hale gelen: adim-listesi, cagri-parametresi, temel-imaj beyan olarak kalan 7: depo, dal, calistirici-turu, yalitim-duzeyi, ag-erisimi, ortam-degiskeni-adlari, onbellek-anahtari
Yeniden üretim kanıt alanını 4’ten 7’ye çıkarır. Kazanılan üç alanın hepsi çıktıya giren girdilerdir: adım listesi, çağrı parametresi ve temel imaj yanlış yazılsaydı yeniden üretilen çıktı tutmazdı. Kalan yedi alan hiçbir koşulda sınanabilir hale gelmez, çünkü çıktıya hiç girmezler. Dal adı, çalıştırıcı türü, yalıtım düzeyi ve önbellek anahtarı üretilen baytları etkilemez; bir şeyi etkilemeyen bildirim de o şeyden geri okunamaz. Belgenin yarısı beyan olarak kalır ve bu bir eksiklik değil, yöntemin sınırıdır.
Ortadaki iki sayı ise kaldıracın bedelidir. On iki yapının dördü eşleşmez ve dördünden yalnız biri gerçektir; üçünde çıktıya bildirilmemiş bir girdi karışmıştır — koşum numarası, üretim anı, çalıştırıcı adı gibi bir değer. Bu üçünde yapı doğrudur, belge doğrudur, değişen tek şey ilan edilmemiş bir girdinin çıktıya sızmasıdır. Yanlış işaret oranı %75’tir ve bu oran taramanın işe yaramadığı durumun tam tanımıdır: dört uyarının üçü boşuna incelenirse dördüncüsü de aynı işaretin altında kalır.
Yanlış işaretin kaynağı da yöntemin kendisindedir. Yeniden üretim, bildirilen girdi kümesinin eksiksiz olduğunu varsayar; eksikse fark çıktıda görünür ama farkın nedeni belgede yazmaz. Eşleşmeyen bir yapının hangi sınıfa girdiğini anlamak için çıktı baytları karşılaştırılır ve sızan değer elle bulunur — bu, uyarı başına ayrı bir inceleme demektir. Üç yanlış işaretin üçü de düzeltilebilir kusurlardır; düzeltmenin yolu belgeye alan eklemek değil, o değeri çıktıdan çıkarmaktır. Kaldıracın kullanılabilir olması için yapının önce ilan edilmemiş girdiden arındırılması gerekir ve bu iş kökene değil, yapı tanımına aittir.
Eşik Yükseldikçe
Üç ölçüm bir politika sorusunu doğurur: dağıtımdan önce hangi eşik aranmalı?
TZ14. Kırk kurgu dağıtım isteği vardır; bozuk istekler de geçerli imza taşır — önceki
dersin sonucudur, imza iddiayı kanıtlamaz. Köken üretimi 12 saniye, yeniden üretim 214 saniye
olarak veri verilmiştir, ölçülmüş değildir; tohum 87344 görünürdür.
// olcum-agi/koken-esigi.mjs — dogrulama esigi yukseldikce gecen, bloke olan ve hattan giden sure const uretec = (tohum) => () => (tohum = (tohum * 1103515245 + 12345) % 2147483648) / 2147483648; const r = uretec(87344); // tohum gorunur // Bozuk istek de gecerli imza tasir: onceki dersin sonucu — imza iddiayi kanitlamaz. const ISTEK = Array.from({ length: 40 }, () => { const bozuk = r() < 0.12; return { bozuk, imzali: true, kokenVar: bozuk || r() < 0.85, kanitUyuyor: !bozuk, gizliGirdi: r() < 0.18 }; // gizli girdi: yeniden uretim eslesmez }); // Sureler VERI olarak verilmistir, olculmus degil: koken uretimi 12 s, yeniden uretim 214 s. const KOKEN_S = 12, TEKRAR_S = 214; const ESIK = [ ["imza yeter", (i) => i.imzali, 0], ["imza + koken belgesi", (i) => i.imzali && i.kokenVar, KOKEN_S], ["imza + dort kanit alani", (i) => i.imzali && i.kokenVar && i.kanitUyuyor, KOKEN_S], ["imza + yeniden uretim", (i) => i.imzali && i.kokenVar && i.kanitUyuyor && !i.gizliGirdi, KOKEN_S + TEKRAR_S], ]; const BOZUK = ISTEK.filter((i) => i.bozuk).length; const S = [26, 9, 9, 14, 0]; const satir = (s) => console.log(s.map((v, i) => String(v).padEnd(S[i])).join("")); satir(["esik", "gecen", "bloke", "yanlis bloke", "kacan bozuk / hat suresi"]); for (const [ad, kural, sure] of ESIK) { const gecen = ISTEK.filter(kural); const bloke = ISTEK.filter((i) => !kural(i)); satir([ad, gecen.length, bloke.length, bloke.filter((i) => !i.bozuk).length, `${gecen.filter((i) => i.bozuk).length} / ${sure * ISTEK.length} s`]); } console.log(""); console.log(`istek ${ISTEK.length}, gercekten bozuk ${BOZUK}, ` + `bildirilmemis girdi tasiyan ${ISTEK.filter((i) => i.gizliGirdi).length}, ` + `koken belgesi olmayan ${ISTEK.filter((i) => !i.kokenVar).length}; tohum 87344`);
esik gecen bloke yanlis bloke kacan bozuk / hat suresi imza yeter 40 0 0 4 / 0 s imza + koken belgesi 35 5 5 4 / 480 s imza + dort kanit alani 31 9 5 0 / 480 s imza + yeniden uretim 26 14 10 0 / 9040 s istek 40, gercekten bozuk 4, bildirilmemis girdi tasiyan 7, koken belgesi olmayan 5; tohum 87344
İkinci satır bu kursun en sık karşılaşılan yanılgısını sayıya çevirir. Köken belgesinin varlığını aramak dört bozuk isteğin dördünü de geçirir — belge bozuk isteklerde de vardır, çünkü belgeyi üreten yapının kendisidir. Karşılığında hattan 480 saniye gider ve beş meşru istek yanlış yere bloke olur. Marjinal değeri sıfır olan bir kapı budur: bir alanı dolduran, hiçbir şeyi karşılaştırmayan bir aşama.
Üçüncü satır aynı 480 saniyeyle dört bozuk isteğin dördünü de tutar. Aradaki fark tek bir işlemdir: belgenin dört kanıt alanı, doğrulayanın kendi elde ettiği nesnelerle karşılaştırılır. Yanlış bloke sayısı değişmez, kaçan bozuk 4’ten 0’a iner. Köken belgesinin değeri üretilmesinde değil, karşılaştırılmasındadır.
Dördüncü satır kaldıracın fiyatını gösterir. Yeniden üretim hiçbir yeni bozuk isteği tutmaz — dördü zaten üçüncü satırda tutulmuştu — ama hat süresini 480 saniyeden 9.040 saniyeye çıkarır ve yanlış bloke sayısını 5’ten 10’a, yani kırk isteğin dörtte birine yükseltir. Kanıt alanını 7’ye çıkarmanın karşılığı budur ve karşılığın ödenip ödenmeyeceği kaçan bozuk sayısına bakılarak karar verilir, alan sayısına bakılarak değil. Dört isteğinden birinin boşuna durduğu bir eşik, eninde sonunda atlanan bir eşiktir.
Özet
- Köken belgesi dört öbekte on dört alandır; 4 alan kanıt, 10 alan beyandır. Kanıt olanların ortak özelliği, doğrulayanın elindeki bir nesnenin özeti olmalarıdır.
- Beyan kalan on alan arasında önemsiz alan yoktur: yalıtım düzeyi, ağ erişimi, çalıştırıcı türü ve temel imaj sınanamaz. Kasten yanlış yazılan beş alanın 3’ü yakalanır, 2’si sınanmaz.
- Yeniden üretim kanıt alanını 4’ten 7’ye çıkarır; kazanılan üç alan çıktıya giren girdilerdir. Kalan 7 alan hiçbir koşulda sınanamaz, çünkü üretilen baytları etkilemez.
- On iki yapının 4’ü yeniden üretimde eşleşmez ve yalnız 1’i gerçektir; yanlış işaret oranı %75’tir.
- Köken belgesinin varlığını aramak 4 bozuk isteğin 4’ünü de geçirir ve 480 saniye alır; aynı süreyle dört kanıt alanını karşılaştırmak kaçan bozuğu 0’a indirir. Yeniden üretim eşiği hiçbir yeni bozuk tutmaz, hat süresini 9.040 saniyeye ve yanlış blokeyi 10’a çıkarır.
Sonraki Adım
Köken belgesi kuruldu, kanıt ile beyan ayrıldı ve eşik yükseltmenin fiyatı yazıldı. Ortada duran şey yedi beyan alanıdır ve bunların dördü doğrudan tek bir konuyu anlatır: yapının hangi ortamda koştuğunu. Çalıştırıcı türü, yalıtım düzeyi, ağ erişimi ve ortam değişkeni adları belgede yazar, hiçbiri sınanamaz — ve sınanamadıkları için değerleri yalnız o ortamın gerçekten öyle kurulmuş olmasına bağlıdır.
Sonraki ders o ortamı kalem kalem sayar. Ölçü artık belgenin alanı değil, derleme ortamının kendi yetkisidir: hat kaç sırra erişiyor, kaçı gerçekten gerekiyor, ağ erişimi kapatıldığında kaç adım kırılıyor ve dış katkıdan gelen bir değişiklik koştuğunda kaç sır açığa çıkabiliyor?
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.