An ECDSA signature.
r: Curve.scalar.CompressedScalarThe R component of an ECDSA signature.
s: Curve.scalar.CompressedScalarThe S component of an ECDSA signature.
Length (in bytes) of a raw signature.
pub const encoded_length = Curve.scalar.encoded_length * 2Maximum length (in bytes) of a DER-encoded signature.
pub const der_encoded_length_max = encoded_length + 2 + 2 * 3anyerror means the error set is known only at runtime.
pub const VerifyError = Verifier.InitError || Verifier.VerifyErrorCreate a Verifier for incremental verification of a signature.
pub fn verify(sig: Signature, msg: []const u8, public_key: PublicKey) VerifyError!voidVerify the signature against a message and public key. Return IdentityElement or NonCanonical if the public key or signature are not in the expected range, or SignatureVerificationError if the signature is invalid for the given message and key.
pub fn verify(sig: Signature, msg: []const u8, public_key: PublicKey) VerifyError!void {
var st = try sig.verifier(public_key);
st.update(msg);
try st.verify();
}pub fn toBytes(sig: Signature) [encoded_length]u8Return the raw signature (r, s) in big-endian format.
sig: Signaturepub fn toBytes(sig: Signature) [encoded_length]u8 {
var bytes: [encoded_length]u8 = undefined;
@memcpy(bytes[0 .. encoded_length / 2], &sig.r);
@memcpy(bytes[encoded_length / 2 ..], &sig.s);
return bytes;
}pub fn fromBytes(bytes: [encoded_length]u8) SignatureCreate a signature from a raw encoding of (r, s). ECDSA always assumes big-endian.
bytes: [encoded_length]u8pub fn fromBytes(bytes: [encoded_length]u8) Signature {
return Signature{
.r = bytes[0 .. encoded_length / 2].*,
.s = bytes[encoded_length / 2 ..].*,
};
}pub fn toDer(sig: Signature, buf: *[der_encoded_length_max]u8) []u8Encode the signature using the DER format. The maximum length of the DER encoding is der_encoded_length_max. The function returns a slice, that can be shorter than der_encoded_length_max.
sig: Signaturebuf: *[der_encoded_length_max]u8pub fn toDer(sig: Signature, buf: *[der_encoded_length_max]u8) []u8 {
var fb = io.fixedBufferStream(buf);
const w = fb.writer();
const r_len = @as(u8, @intCast(sig.r.len + (sig.r[0] >> 7)));
const s_len = @as(u8, @intCast(sig.s.len + (sig.s[0] >> 7)));
const seq_len = @as(u8, @intCast(2 + r_len + 2 + s_len));
w.writeAll(&[_]u8{ 0x30, seq_len }) catch unreachable;
w.writeAll(&[_]u8{ 0x02, r_len }) catch unreachable;
if (sig.r[0] >> 7 != 0) {
w.writeByte(0x00) catch unreachable;
}
w.writeAll(&sig.r) catch unreachable;
w.writeAll(&[_]u8{ 0x02, s_len }) catch unreachable;
if (sig.s[0] >> 7 != 0) {
w.writeByte(0x00) catch unreachable;
}
w.writeAll(&sig.s) catch unreachable;
return fb.getWritten();
}pub fn fromDer(der: []const u8) EncodingError!SignatureCreate a signature from a DER representation. Returns InvalidEncoding if the DER encoding is invalid.
der: []const u8pub fn fromDer(der: []const u8) EncodingError!Signature {
var sig: Signature = mem.zeroInit(Signature, .{});
var fb = io.fixedBufferStream(der);
const reader = fb.reader();
var buf: [2]u8 = undefined;
_ = reader.readNoEof(&buf) catch return error.InvalidEncoding;
if (buf[0] != 0x30 or @as(usize, buf[1]) + 2 != der.len) {
return error.InvalidEncoding;
}
try readDerInt(&sig.r, reader);
try readDerInt(&sig.s, reader);
if (fb.getPos() catch unreachable != der.len) return error.InvalidEncoding;
return sig;
}pub const Signature = struct {
/// Length (in bytes) of a raw signature.
pub const encoded_length = Curve.scalar.encoded_length * 2;
/// Maximum length (in bytes) of a DER-encoded signature.
pub const der_encoded_length_max = encoded_length + 2 + 2 * 3;
/// The R component of an ECDSA signature.
r: Curve.scalar.CompressedScalar,
/// The S component of an ECDSA signature.
s: Curve.scalar.CompressedScalar,
/// Create a Verifier for incremental verification of a signature.
pub fn verifier(sig: Signature, public_key: PublicKey) Verifier.InitError!Verifier {
return Verifier.init(sig, public_key);
}
pub const VerifyError = Verifier.InitError || Verifier.VerifyError;
/// Verify the signature against a message and public key.
/// Return IdentityElement or NonCanonical if the public key or signature are not in the expected range,
/// or SignatureVerificationError if the signature is invalid for the given message and key.
pub fn verify(sig: Signature, msg: []const u8, public_key: PublicKey) VerifyError!void {
var st = try sig.verifier(public_key);
st.update(msg);
try st.verify();
}
/// Return the raw signature (r, s) in big-endian format.
pub fn toBytes(sig: Signature) [encoded_length]u8 {
var bytes: [encoded_length]u8 = undefined;
@memcpy(bytes[0 .. encoded_length / 2], &sig.r);
@memcpy(bytes[encoded_length / 2 ..], &sig.s);
return bytes;
}
/// Create a signature from a raw encoding of (r, s).
/// ECDSA always assumes big-endian.
pub fn fromBytes(bytes: [encoded_length]u8) Signature {
return Signature{
.r = bytes[0 .. encoded_length / 2].*,
.s = bytes[encoded_length / 2 ..].*,
};
}
/// Encode the signature using the DER format.
/// The maximum length of the DER encoding is der_encoded_length_max.
/// The function returns a slice, that can be shorter than der_encoded_length_max.
pub fn toDer(sig: Signature, buf: *[der_encoded_length_max]u8) []u8 {
var fb = io.fixedBufferStream(buf);
const w = fb.writer();
const r_len = @as(u8, @intCast(sig.r.len + (sig.r[0] >> 7)));
const s_len = @as(u8, @intCast(sig.s.len + (sig.s[0] >> 7)));
const seq_len = @as(u8, @intCast(2 + r_len + 2 + s_len));
w.writeAll(&[_]u8{ 0x30, seq_len }) catch unreachable;
w.writeAll(&[_]u8{ 0x02, r_len }) catch unreachable;
if (sig.r[0] >> 7 != 0) {
w.writeByte(0x00) catch unreachable;
}
w.writeAll(&sig.r) catch unreachable;
w.writeAll(&[_]u8{ 0x02, s_len }) catch unreachable;
if (sig.s[0] >> 7 != 0) {
w.writeByte(0x00) catch unreachable;
}
w.writeAll(&sig.s) catch unreachable;
return fb.getWritten();
}
// Read a DER-encoded integer.
fn readDerInt(out: []u8, reader: anytype) EncodingError!void {
var buf: [2]u8 = undefined;
_ = reader.readNoEof(&buf) catch return error.InvalidEncoding;
if (buf[0] != 0x02) return error.InvalidEncoding;
var expected_len = @as(usize, buf[1]);
if (expected_len == 0 or expected_len > 1 + out.len) return error.InvalidEncoding;
var has_top_bit = false;
if (expected_len == 1 + out.len) {
if ((reader.readByte() catch return error.InvalidEncoding) != 0) return error.InvalidEncoding;
expected_len -= 1;
has_top_bit = true;
}
const out_slice = out[out.len - expected_len ..];
reader.readNoEof(out_slice) catch return error.InvalidEncoding;
if (has_top_bit and out[0] >> 7 == 0) return error.InvalidEncoding;
}
/// Create a signature from a DER representation.
/// Returns InvalidEncoding if the DER encoding is invalid.
pub fn fromDer(der: []const u8) EncodingError!Signature {
var sig: Signature = mem.zeroInit(Signature, .{});
var fb = io.fixedBufferStream(der);
const reader = fb.reader();
var buf: [2]u8 = undefined;
_ = reader.readNoEof(&buf) catch return error.InvalidEncoding;
if (buf[0] != 0x30 or @as(usize, buf[1]) + 2 != der.len) {
return error.InvalidEncoding;
}
try readDerInt(&sig.r, reader);
try readDerInt(&sig.s, reader);
if (fb.getPos() catch unreachable != der.len) return error.InvalidEncoding;
return sig;
}
}