this repo has no description
at main 133 lines 4.6 kB view raw
1const std = @import("std"); 2const crypto = std.crypto; 3const Secp256k1 = crypto.ecc.Secp256k1; 4const Sha256 = crypto.hash.sha2.Sha256; 5const scalar = Secp256k1.scalar; 6 7const verify_mod = @import("verify.zig"); 8 9// re-export internals for testing 10pub const field = @import("field.zig"); 11pub const endo = @import("endo.zig"); 12pub const point = @import("point.zig"); 13pub const verify = @import("verify.zig"); 14pub const jacobian = @import("jacobian.zig"); 15pub const affine = @import("affine.zig"); 16 17/// Drop-in replacement for std.crypto.sign.ecdsa.EcdsaSecp256k1Sha256 18/// with optimized verification (~3.6x faster). 19/// Signing delegates to stdlib (not the bottleneck). 20pub const EcdsaSecp256k1Sha256 = struct { 21 const Curve = Secp256k1; 22 const Hash = Sha256; 23 const StdEcdsa = crypto.sign.ecdsa.EcdsaSecp256k1Sha256; 24 25 pub const Signature = struct { 26 pub const encoded_length = 64; 27 28 r: [32]u8, 29 s: [32]u8, 30 31 pub fn fromBytes(bytes: [64]u8) Signature { 32 return .{ .r = bytes[0..32].*, .s = bytes[32..64].* }; 33 } 34 35 pub fn toBytes(sig: Signature) [64]u8 { 36 var buf: [64]u8 = undefined; 37 @memcpy(buf[0..32], &sig.r); 38 @memcpy(buf[32..64], &sig.s); 39 return buf; 40 } 41 42 /// Verify this signature against a message and public key. 43 pub fn verifyMsg(sig: Signature, msg: []const u8, public_key: PublicKey) VerifyError!void { 44 var h = Sha256.init(.{}); 45 h.update(msg); 46 const digest = h.finalResult(); 47 return sig.verifyPrehashed(digest, public_key); 48 } 49 50 /// Verify this signature against a pre-hashed message. 51 pub fn verifyPrehashed(sig: Signature, msg_hash: [32]u8, public_key: PublicKey) VerifyError!void { 52 return verify_mod.verify(sig.r, sig.s, msg_hash, public_key.p); 53 } 54 55 /// Create a streaming verifier. 56 pub fn verifier(sig: Signature, public_key: PublicKey) InitError!Verifier { 57 return Verifier.init(sig, public_key); 58 } 59 60 /// DER encoding support. 61 pub const der_encoded_length_max = encoded_length + 2 + 2 * 3; 62 63 pub fn toDer(sig: Signature, buf: *[der_encoded_length_max]u8) []u8 { 64 const std_sig = StdEcdsa.Signature{ .r = sig.r, .s = sig.s }; 65 return std_sig.toDer(buf); 66 } 67 68 pub fn fromDer(der: []const u8) crypto.errors.EncodingError!Signature { 69 const std_sig = try StdEcdsa.Signature.fromDer(der); 70 return .{ .r = std_sig.r, .s = std_sig.s }; 71 } 72 }; 73 74 pub const PublicKey = struct { 75 pub const compressed_sec1_encoded_length = 33; 76 pub const uncompressed_sec1_encoded_length = 65; 77 78 p: Curve, 79 80 pub fn fromSec1(sec1: []const u8) !PublicKey { 81 const pt = try Curve.fromSec1(sec1); 82 return .{ .p = pt }; 83 } 84 85 pub fn toCompressedSec1(pk: PublicKey) [33]u8 { 86 return pk.p.toCompressedSec1(); 87 } 88 89 pub fn toUncompressedSec1(pk: PublicKey) [65]u8 { 90 return pk.p.toUncompressedSec1(); 91 } 92 }; 93 94 /// Delegate to stdlib for signing (not the bottleneck). 95 pub const SecretKey = StdEcdsa.SecretKey; 96 pub const KeyPair = StdEcdsa.KeyPair; 97 98 pub const InitError = verify_mod.VerifyError; 99 pub const VerifyError = verify_mod.VerifyError; 100 101 /// Streaming verifier: feed data incrementally, then verify. 102 pub const Verifier = struct { 103 h: Sha256, 104 sig: Signature, 105 public_key: PublicKey, 106 107 pub fn init(sig: Signature, public_key: PublicKey) InitError!Verifier { 108 // validate r, s upfront 109 const r = scalar.Scalar.fromBytes(sig.r, .big) catch return error.SignatureVerificationFailed; 110 const s = scalar.Scalar.fromBytes(sig.s, .big) catch return error.SignatureVerificationFailed; 111 if (r.isZero() or s.isZero()) return error.IdentityElement; 112 return .{ .h = Sha256.init(.{}), .sig = sig, .public_key = public_key }; 113 } 114 115 pub fn update(self: *Verifier, data: []const u8) void { 116 self.h.update(data); 117 } 118 119 pub fn verify(self: *Verifier) VerifyError!void { 120 const digest = self.h.finalResult(); 121 return self.sig.verifyPrehashed(digest, self.public_key); 122 } 123 }; 124}; 125 126test { 127 _ = @import("field.zig"); 128 _ = @import("endo.zig"); 129 _ = @import("point.zig"); 130 _ = @import("verify.zig"); 131 _ = @import("jacobian.zig"); 132 _ = @import("affine.zig"); 133}