this repo has no description
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}