Açık anahtar (asimetrik) kriptografi, paylaşılan bir gizli değer yerine bir anahtar çifti kullanır: özel anahtarın imzaladığı her şeyi, eşleşen açık anahtar doğrular; bir açık anahtara mühürlenen her şeyi yalnızca eşleşen özel anahtar açar. Açık anahtar, bir düşman dahil olmak üzere herhangi birine, hiçbir şeyi zayıflatmadan verilebilir.
RSA
Anahtar üretimi büyük asal sayılar arar ve gerçekten yavaştır; 2048 bitlik bir anahtar için birkaç saniye sürer; bunu asla bir arayüz iş parçacığında çalıştırmayın. Şifreleme için OAEP, imzalar için PSS kullanın; ikisi de PKCS#1 v1.5'in eksik olduğu rastgeleleştirilmiş bir unsur içerir. PKCS#1 v1.5 imzala/doğrula, bunu belirten biçimlerle (JWS RS256 yaygın durumdur) birlikte çalışmak için sgcCrypto_RSA içinde sağlanır; yeni herhangi bir şey için PSS'i tercih edin.
function sgcRSA_GenerateKey(aBits: Integer): TsgcRSAPrivateKey;
function sgcRSA_PublicKey(const aPrivateKey: TsgcRSAPrivateKey): TsgcRSAPublicKey;
function sgcRSA_OAEP_Encrypt(const aKey: TsgcRSAPublicKey; const aPlain, aLabel: TBytes; aHash: TsgcRSAHash): TBytes;
function sgcRSA_OAEP_Decrypt(const aKey: TsgcRSAPrivateKey; const aCipher, aLabel: TBytes; aHash: TsgcRSAHash; out aPlain: TBytes): Boolean;
function sgcRSA_PSS_Sign(const aKey: TsgcRSAPrivateKey; const aData: TBytes; aHash: TsgcRSAHash; aSaltLen: Integer = -1): TBytes;
function sgcRSA_PSS_Verify(const aKey: TsgcRSAPublicKey; const aData, aSignature: TBytes; aHash: TsgcRSAHash; aSaltLen: Integer = -1): Boolean;
var
oKey: TsgcRSAPrivateKey;
oSignature: TBytes;
begin
oKey := sgcRSA_GenerateKey(2048);
oSignature := sgcRSA_PSS_Sign(oKey, oData, rhSHA256);
if sgcRSA_PSS_Verify(sgcRSA_PublicKey(oKey), oData, oSignature, rhSHA256) then
{ valid };
end;
PKCS#1 v1.5 şifreleme de sağlanır; Java'nın RSA/NONE/PKCS1Padding olarak adlandırdığı mod budur. Bu, yalnızca bunu zorunlu kılan biçimlerle birlikte çalışmak içindir, başka hiçbir şey için değil: v1.5 dolgusu tam olarak Bleichenbacher saldırısının hedef aldığı şeydir, bu yüzden yeni herhangi bir şey için doğru seçim OAEP olmaya devam eder. Düz metin, modül boyutu eksi 11 bayt ile sınırlıdır; 2048 bitlik bir anahtarla 245 bayt.
function sgcRSA_PKCS1_Encrypt(const aKey: TsgcRSAPublicKey; const aPlain: TBytes): TBytes;
function sgcRSA_PKCS1_Decrypt(const aKey: TsgcRSAPrivateKey; const aCipher: TBytes; out aPlain: TBytes): Boolean;
sgcRSA_PKCS1_Decrypt, her tür kod çözme başarısızlığı için False döndürür ve bunların hepsi için aynı yoldan geçer, çünkü bunları birbirinden ayırt etmek tam olarak bir padding oracle'ın ihtiyaç duyduğu şeydir.
Ayrı bir MGF1 hash'i ile OAEP
OAEP, bir hash'i iki yerde kullanır: etiket üzerinde ve MGF1 maske üretme fonksiyonunun içinde, ve ikisinin aynı olması gerekmez. Java'nın ısırdığı yer tam olarak burasıdır. SunJCE, OAEPWithSHA256AndMGF1Padding'i özet için SHA-256, MGF1 için hâlâ SHA-1 olarak okurken, Bouncy Castle aynı dizeyi ikisi için de SHA-256 olarak okur; bu yüzden birinin ürettiği bir şifreli metin diğeri tarafından çözülemez. Beş parametreli aşırı yüklemeler, iki hash'i birbirinden bağımsız olarak sabitler; bir Java eşiyle konuşmanın gerektirebileceği şey budur. Dört parametreli biçim değişmeden kalır ve ikisi için de aHash'i geçirir.
function sgcRSA_OAEP_Encrypt(const aKey: TsgcRSAPublicKey; const aPlain, aLabel: TBytes; aHash, aMGFHash: TsgcRSAHash): TBytes; overload;
function sgcRSA_OAEP_Decrypt(const aKey: TsgcRSAPrivateKey; const aCipher, aLabel: TBytes; aHash, aMGFHash: TsgcRSAHash; out aPlain: TBytes): Boolean; overload;
var
oKey: TsgcRSAPrivateKey;
oCipher: TBytes;
begin
{ SunJCE OAEPWithSHA256AndMGF1Padding: SHA-256 etiket hash'i, MGF1 SHA-1 üzerinde. }
oCipher := sgcRSA_OAEP_Encrypt(sgcRSA_PublicKey(oKey), oPlain, nil, rhSHA256, rhSHA1);
end;
Bir hash uyuşmazlığı, bozuk bir şifreli metinden ayırt edilemez, bu yüzden yanlış bir aMGFHash, ikisinden hangisinin yanlış olduğunu söylemeden sade bir False olarak geri döner. Her iki eş de bunu önceden kararlaştırmak zorundadır.
Anahtarlar PKCS#1 ve SubjectPublicKeyInfo DER'e ve PEM'e dışa aktarılır:
function sgcRSA_ExportPrivateKeyPEM(const aKey: TsgcRSAPrivateKey): string;
function sgcRSA_ExportPublicKeyPEM(const aKey: TsgcRSAPublicKey): string;
PKCS#8, diğer özel anahtar kabıdır; BEGIN PRIVATE KEY olarak yazılan ve Java ile .NET'in beklediği budur; yukarıdaki çift bunun yerine daha eski PKCS#1 BEGIN RSA PRIVATE KEY'i üretir. Kabın hiçbiri şifreli değildir, bu yüzden geri dönen şey çıplak anahtar malzemesidir ve bir günlüğün veya bir yedeklemenin erişebileceği hiçbir yere ait değildir.
function sgcRSA_ExportPrivateKeyPKCS8DER(const aKey: TsgcRSAPrivateKey): TBytes;
function sgcRSA_ExportPrivateKeyPKCS8PEM(const aKey: TsgcRSAPrivateKey): string;
Bir RSA anahtarını içe aktarma
Bunlar var olana kadar bir TsgcRSAPrivateKey yalnızca sgcRSA_GenerateKey'den çıkabiliyordu; bu da diske kaydedilmiş bir anahtarın hiç kullanılamayacağı anlamına geliyordu. İçe aktarma rutinleri, her iki özel anahtar kabını da, PKCS#1 RSAPrivateKey ve PKCS#8 PrivateKeyInfo, ve her iki açık anahtar kodlamasını da, PKCS#1 RSAPublicKey ve X.509 SubjectPublicKeyInfo, DER veya PEM olarak okur. Şifreli bir PKCS#8, yani BEGIN ENCRYPTED PRIVATE KEY biçimi, desteklenmez ve False döndürür. CRT parametreleri, dosya bunları atladığında yeniden hesaplanır, bu yüzden içe aktarılan bir anahtar yine de tam hızda çalışır.
function sgcRSA_ImportPrivateKeyDER(const aDER: TBytes; out aKey: TsgcRSAPrivateKey): Boolean;
function sgcRSA_ImportPrivateKeyPEM(const aPEM: string; out aKey: TsgcRSAPrivateKey): Boolean;
function sgcRSA_ImportPublicKeyDER(const aDER: TBytes; out aKey: TsgcRSAPublicKey): Boolean;
function sgcRSA_ImportPublicKeyPEM(const aPEM: string; out aKey: TsgcRSAPublicKey): Boolean;
var
oKey: TsgcRSAPrivateKey;
oSignature: TBytes;
begin
if sgcRSA_ImportPrivateKeyPEM(Memo1.Text, oKey) then
oSignature := sgcRSA_PSS_Sign(oKey, oData, rhSHA256);
end;
Bir sertifika bir açık anahtar değildir, bu yüzden sgcRSA_ImportPublicKeyDER'e sertifikanın kendisini değil, sertifikadan çıkarılan SubjectPublicKeyInfo'yu verin. sgcRSA_CheckPrivateKey, başka bir yerden gelen herhangi bir şeyin iç tutarlılığını doğrular: n = p*q olduğunu, e*d'nin 1'e uyumlu (congruent) olduğunu ve CRT parametrelerinin eşleştiğini.
Ed25519 ve Ed448 (imzalar)
EdDSA nonce'ları özel anahtardan ve mesajdan deterministik olarak türetilir, bu yüzden imzalamada bir rastgele sayı üretecine gerek kalmaz ve ECDSA'nın aksine (aşağıya bakın) anahtarı sızdıran tekrarlanan bir nonce olasılığı yoktur. sgcCrypto_Ed25519, sgcWebSockets'in başka bir yerindeki WebAuthn EdDSA kimlik bilgisi türü tarafından kullanılan doğrula/imzala ilkesidir; çağıranın 32 baytlık açık anahtarı zaten bildiğini varsayar (WebAuthn bunu size kimlik bilgisinden verir) ve ayrı bir anahtar üretimi veya açık-anahtar-türetme çağrısı sunmaz. sgcCrypto_Ed448, Ed25519 için 128'e karşı kabaca 224 bit güvenlik sunan, daha büyük bir anahtar ve imza ve daha yavaş imzalama pahasına, genel amaçlı imzalayıcıdır.
{ Ed25519: caller supplies the 32-byte seed and, to verify, the 32-byte public key. }
function sgcEd25519_Sign(const aPrivateSeed, aMessage: TBytes): TBytes;
function sgcEd25519_Verify(const aPublicKey, aMessage, aSignature: TBytes): Boolean;
{ Ed448: 57-byte keys, 114-byte signatures, optional context string. }
procedure sgcEd448_GenerateKeyPair(out aPrivateKey, aPublicKey: TBytes);
function sgcEd448_Sign(const aPrivateKey, aMessage, aContext: TBytes): TBytes;
function sgcEd448_Verify(const aPublicKey, aMessage, aSignature, aContext: TBytes): Boolean;
X25519 ve X448 (anahtar anlaşması)
Montgomery eğrileri üzerinde Diffie-Hellman: her iki taraf da bir anahtar çifti üretir, açık anahtarları değiş tokuş eder ve her biri kendi özel anahtarından ve diğer tarafın açık anahtarından aynı paylaşılan gizli değeri hesaplar. Bir şeyi şifrelemek için kullanmadan önce ham çıktıyı her zaman bir KDF'den geçirin (bkz. Parola Hash'leme ve Anahtar Türetme, HKDF); ham ECDH çıktısının kendisi uygun bir anahtar değildir. X448, X25519 için 128'e karşı kabaca 224 bit güvenlik sunar; daha büyük bir anahtar ve yaklaşık üç kat daha fazla hesaplama pahasına.
function sgcX25519_PublicKey(const aPrivateKey: TBytes): TBytes;
function sgcX25519_SharedSecret(const aPrivateKey, aPeerPublicKey: TBytes; out aSecret: TBytes): Boolean;
function sgcX448_PublicKey(const aPrivateKey: TBytes): TBytes;
function sgcX448_SharedSecret(const aPrivateKey, aPeerPublicKey: TBytes; out aSecret: TBytes): Boolean;
var
oAlicePriv, oBobPriv, oAlicePub, oBobPub, oSecretA, oSecretB: TBytes;
begin
oAlicePriv := sgcRandomBytes(32);
oBobPriv := sgcRandomBytes(32);
oAlicePub := sgcX25519_PublicKey(oAlicePriv);
oBobPub := sgcX25519_PublicKey(oBobPriv);
sgcX25519_SharedSecret(oAlicePriv, oBobPub, oSecretA);
sgcX25519_SharedSecret(oBobPriv, oAlicePub, oSecretB);
{ oSecretA = oSecretB }
end;
SharedSecret, düşük dereceli bir eş anahtarı için False döndürür; bu, kendi özel anahtarınızdan bağımsız olarak paylaşılan gizli değeri tamamen sıfıra zorlayan küçük bir açık anahtar kümesidir. Her zaman sonucu koşulsuz olarak güvenmek yerine kontrol edin.
ECIES (mühürlü kutu şifrelemesi)
X25519, HKDF-SHA256 ve XChaCha20-Poly1305'i, önceden paylaşılan bir gizli değere ihtiyaç duymadan bir mesajı bir alıcının açık anahtarına şifreleyen tek bir çağrıda birleştirir. aContext, mühürlü mesajı bir amaca veya protokol adımına bağlar; farklı bir bağlam altında açmak başarısız olur, bu da bir değiş tokuştan mühürlü bir mesajın başka birine tekrar oynatılmasını engeller.
procedure sgcECIES_GenerateKeyPair(out aPrivateKey, aPublicKey: TBytes);
function sgcECIES_Seal(const aRecipientPublicKey, aPlain, aAAD, aContext: TBytes): TBytes;
function sgcECIES_Open(const aPrivateKey, aSealed, aAAD, aContext: TBytes; out aPlain: TBytes): Boolean;
Adlandırılmış eğriler üzerinde ECDSA / ECDH
İki ayrı birim, kısa Weierstrass eğrilerini, hangi eğri ailesini uyguladıklarına göre bölünmüş olarak kapsar:
sgcCrypto_EC, NIST eğrilerini (P-256, P-384, P-521) kapsar ve PEM anahtarları ile JWS imzaları etrafında, JWT kütüphanelerinin beklediği biçimde (ES256 ve benzerleri) yönlendirilmiştir.
sgcCrypto_ECCurves, secp256k1'i (Bitcoin ve Ethereum eğrisi) ve RFC 5639'un brainpoolP256r1 / P384r1 / P512r1 eğrilerini kapsar; PEM yerine doğrudan ham anahtar ve imza baytları üzerinde çalışır.
sgcCrypto_ECCurves içindeki TsgcECCurve artık dörde değil, yediye eğri adlandırıyor: eccSecp256k1, üç Brainpool eğrisi, ve NIST P-256, P-384 ve P-521 için eccP256, eccP384 ve eccP521. NIST'in üçüne daha önce yalnızca sgcCrypto_EC'nin PEM ve JWS API'si üzerinden ulaşılabiliyordu, bu yüzden bir P-256 anahtarını ham bayt olarak tutan bir uygulamanın önce PEM yazması gerekiyordu. Aşağıdaki ham anahtar üretme, imzalama, doğrulama, ECDH ve sıkıştırma çağrıları artık yedisini de kapsıyor. İş JWS ise sgcCrypto_EC'ye, anahtar malzemesi zaten baytlarsa sgcCrypto_ECCurves'e başvurun.
Her iki birim de TsgcECCurve adında bir tür ve sgcEC_GenerateKeyPair adında bir rutin bildirir; her birimde farklı anlamlarla. İki birimi aynı uses cümlesine eklemeyin ve herhangi bir ismi niteliksiz olarak referans göstermeyin; tek bir birim gerçekten ikisine de ihtiyaç duyuyorsa birim adıyla niteleyin (sgcCrypto_ECCurves.sgcEC_GenerateKeyPair).
{ sgcCrypto_ECCurves: secp256k1 and Brainpool, RFC 6979 deterministic nonces,
low-S normalized signatures (BIP 62). }
procedure sgcEC_GenerateKeyPair(aCurve: TsgcECCurve; out aPrivateKey, aPublicKey: TBytes);
function sgcECDSA_SignHash(aCurve: TsgcECCurve; const aPrivateKey, aHash: TBytes; aHashKind: TsgcECHash = echSHA256): TBytes;
function sgcECDSA_VerifyHash(aCurve: TsgcECCurve; const aPublicKey, aHash, aSignature: TBytes): Boolean;
function sgcECDH_SharedSecret(aCurve: TsgcECCurve; const aPrivateKey, aPeerPublicKey: TBytes; out aSecret: TBytes): Boolean;
function sgcEC_ValidatePublicKey(aCurve: TsgcECCurve; const aPublicKey: TBytes): Boolean;
function sgcEC_Compress(aCurve: TsgcECCurve; const aPublicKey: TBytes): TBytes;
function sgcEC_Decompress(aCurve: TsgcECCurve; const aCompressed: TBytes): TBytes;
Buradaki ECDSA imzaları RFC 6979 deterministik nonce'ları kullanır: nonce, bir rastgele sayı üretecinden çekilmek yerine özel anahtardan ve mesajdan türetilir; bu da gerçek konuşlandırmaların bir ECDSA özel anahtarını kaybetmesinin en yaygın tek yolunu, tekrarlanan veya kısmen tahmin edilebilir bir nonce'u ortadan kaldırır. İmzalar, Bitcoin'in (BIP 62) ve Ethereum'un gerektirdiği düşük-S normalleştirmesini taşır; doğrulama her iki biçimi de kabul eder.
DER kodlu ECDSA imzaları
Tek bir imza, iki kodlama, ve yanlışını seçmek bu alandaki en yaygın entegrasyon hatalarından biridir. Her yarısı eğri alan boyutu kadar olan ham çift R || S, JOSE'nin ve WebAuthn'ın taşıdığı şeydir. Bir DER SEQUENCE { r, s }, X.509'un, CMS'nin ve TLS'in taşıdığı şeydir. Yukarıdaki sgcECDSA_SignHash ham biçimi üretir, aşağıdaki çağrılar DER biçimini üretir ve tüketir, ve iki dönüştürücü hiçbir şeyi yeniden imzalamadan aralarında çeviri yapar.
{ sgcCrypto_ECCurves: ham anahtarlar, çağıranın zaten hesapladığı bir özet. }
function sgcECDSA_SignDER(aCurve: TsgcECCurve; const aPrivateKey, aHash: TBytes; aHashKind: TsgcECHash): TBytes; overload;
function sgcECDSA_VerifyDER(aCurve: TsgcECCurve; const aPublicKey, aHash, aDERSignature: TBytes): Boolean; overload;
function sgcECDSA_RawToDER(aCurve: TsgcECCurve; const aRaw: TBytes): TBytes;
function sgcECDSA_DERToRaw(aCurve: TsgcECCurve; const aDER: TBytes; out aRaw: TBytes): Boolean;
{ sgcCrypto_EC: PEM anahtarları, aData'nın kendisini eğrinin SHA'sıyla hash'ler. }
function sgcECDSA_SignDER(const aPrivateKeyPEM: string; const aData: TBytes; aCurveBits: Integer): TBytes; overload;
function sgcECDSA_VerifyDER(const aPublicPoint, aData, aDERSignature: TBytes; aCurveBits: Integer): Boolean; overload;
var
oRaw, oDER: TBytes;
begin
oRaw := sgcECDSA_SignHash(eccP256, oPrivateKey, oDigest, echSHA256);
oDER := sgcECDSA_RawToDER(eccP256, oRaw);
end;
aHashKind, ham anahtar biçiminde yalnızca RFC 6979 nonce'ının arkasındaki HMAC'ı seçer, sizin için hiçbir şeyi hash'lemez, bu yüzden başka türlü seçmek için bir neden yoksa sgcEC_DefaultHash(aCurve)'i geçirin. sgcECDSA_RawToDER, çift tam olarak iki alan boyutu yarısı değilse boş bir dizi döndürür, ve sgcECDSA_DERToRaw, bozuk DER'de veya eğriye uymayan bir değerde False döndürür; bu yüzden ikisini de güvenilmeyen girdiye yöneltmek güvenlidir.
EC anahtarlarını dışa ve içe aktarma
Üç kap, ve bunları birbirinden ayıran şey PEM etiketidir: bir SEC1 ECPrivateKey, BEGIN EC PRIVATE KEY'dir; bir PKCS#8 PrivateKeyInfo, BEGIN PRIVATE KEY'dir; ve bir X.509 SubjectPublicKeyInfo, BEGIN PUBLIC KEY'dir. Java ve .NET, PKCS#8 ister; OpenSSL ve çoğu komut satırı aracı ikisini de okur. Özel biçimlerin hiçbiri şifreli değildir, bu yüzden sonuç, skalerin kendisi kadar gizlidir.
function sgcEC_ExportPrivateKeySEC1DER(aCurve: TsgcECCurve; const aPrivateKey, aPublicKey: TBytes): TBytes;
function sgcEC_ExportPrivateKeyPKCS8DER(aCurve: TsgcECCurve; const aPrivateKey, aPublicKey: TBytes): TBytes;
function sgcEC_ExportSubjectPublicKeyInfo(aCurve: TsgcECCurve; const aPublicKey: TBytes): TBytes;
function sgcEC_ExportPrivateKeySEC1PEM(aCurve: TsgcECCurve; const aPrivateKey, aPublicKey: TBytes): string;
function sgcEC_ExportPrivateKeyPKCS8PEM(aCurve: TsgcECCurve; const aPrivateKey, aPublicKey: TBytes): string;
function sgcEC_ExportPublicKeyPEM(aCurve: TsgcECCurve; const aPublicKey: TBytes): string;
function sgcEC_ImportPrivateKeyDER(const aDER: TBytes; out aCurve: TsgcECCurve; out aPrivateKey, aPublicKey: TBytes): Boolean;
function sgcEC_ImportPrivateKeyPEM(const aPEM: string; out aCurve: TsgcECCurve; out aPrivateKey, aPublicKey: TBytes): Boolean;
function sgcEC_ImportPublicKeyDER(const aDER: TBytes; out aCurve: TsgcECCurve; out aPublicKey: TBytes): Boolean;
function sgcEC_ImportPublicKeyPEM(const aPEM: string; out aCurve: TsgcECCurve; out aPublicKey: TBytes): Boolean;
var
oCurve: TsgcECCurve;
oPrivateKey, oPublicKey: TBytes;
begin
if sgcEC_ImportPrivateKeyPEM(Memo1.Text, oCurve, oPrivateKey, oPublicKey) then
Memo2.Text := sgcEC_ExportPrivateKeyPKCS8PEM(oCurve, oPrivateKey, oPublicKey);
end;
İçe aktarma rutinleri eğriyi dosyadan okur, bu yüzden aCurve, geçirilmek yerine bir out parametresi olarak geri döner. Birimin uygulamadığı bir eğri, bir hata değil bir anlaşma başarısızlığıdır, bu yüzden False döndürürler ve asla raise etmezler; bu da onları güvenilmeyen girdide güvenli kılar. Açık nokta, dosya bunu atladığında skalerden yeniden hesaplanır ve geri verilmeden önce eğriye karşı doğrulanır. Dışa aktarma rutinleri bunun yerine raise eder, çünkü eğriyle eşleşmeyen anahtar malzemesi bir girdi değil, bir çağıran hatasıdır.
Bu kapların her birine giren noktalı adlandırılmış eğri OID'i doğrudan kullanılabilir ve dışa ve içe aktarma rutinlerinin dahili olarak kullandığı şeydir:
function sgcEC_CurveOID(aCurve: TsgcECCurve): string;
function sgcEC_CurveFromOID(const aDotted: string; out aCurve: TsgcECCurve): Boolean;
Her zaman bir eşin açık anahtarını doğrulayın
Kendinizin üretmediği herhangi bir açık anahtarı kullanmadan önce (ECDH, ECDSA doğrulaması veya ECIES için olsun), bunun gerçekten eğri üzerinde bir nokta olduğunu sgcEC_ValidatePublicKey ile doğrulayın. Eğri üzerinde olmayan bir nokta, onu işlemek için kullanılan aritmetik yoluyla kendi özel anahtarınızın bitlerini sızdırabilir.
Schnorr imzaları (BIP-340)
Yalnızca secp256k1, ve Taproot, Nostr ve Lightning'in kullandığı budur. Yukarıdaki ECDSA için doğrudan bir yerine geçen değildir, çünkü iki şey farklıdır. Açık anahtarlar yalnızca-x'tir, y koordinatının çift olduğu varsayılan 32 bayttır; bu yüzden bir BIP-340 anahtarı, bu sayfanın geri kalanının ürettiği 33 baytlık sıkıştırılmış veya 65 baytlık sıkıştırılmamış biçimlerle değiştirilebilir değildir. Ve meydan okuma (challenge), açık anahtarı nonce ve mesajla birlikte hash'ler; bu da imzayı, bir ECDSA imzasının yapmadığı bir şekilde anahtara bağlar.
function sgcSchnorr_PublicKey(const aPrivateKey: TBytes): TBytes;
function sgcSchnorr_Sign(const aPrivateKey, aMessage, aAuxRand: TBytes): TBytes;
function sgcSchnorr_Verify(const aPublicKey, aMessage, aSignature: TBytes): Boolean;
function sgcSchnorr_TaggedHash(const aTag: string; const aData: TBytes): TBytes;
var
oPrivateKey, oPublicKey, oSignature: TBytes;
begin
oPrivateKey := sgcRandomBytes(32);
oPublicKey := sgcSchnorr_PublicKey(oPrivateKey); { 32 bayt, yalnızca-x }
oSignature := sgcSchnorr_Sign(oPrivateKey, oMessage, sgcRandomBytes(32));
if sgcSchnorr_Verify(oPublicKey, oMessage, oSignature) then
{ valid };
end;
aAuxRand, nonce türetmeye karıştırılan 32 baytlık yardımcı rastgeleliktir. Bu, nonce'un kendisi değil, hata saldırılarına (fault attacks) karşı derinlemesine savunmadır: şema, bu tamamen sıfır olsa bile güvenli kalır, ve boş bir dizi 32 sıfır bayt olarak ele alınır; böylece BIP-340 test vektörleri tam olarak yeniden üretilebilir. Gerçek kullanım taze rastgelelik geçirmelidir. sgcSchnorr_TaggedHash, BIP-341 ve BIP-342'nin aynı yapı üzerine ek etiketler inşa etmesi nedeniyle dışa açılmıştır.