A Verifier is used to incrementally verify a signature.
It can be obtained from a Signature, using the verifier() function.
anyerror means the error set is known only at runtime.
pub const InitError = IdentityElementError || NonCanonicalErroranyerror means the error set is known only at runtime.
pub const VerifyError = IdentityElementError || NonCanonicalError ||
SignatureVerificationErrorpub fn update(self: *Verifier, data: []const u8) voidAdd new content to the message to be verified.
self: *Verifierdata: []const u8pub fn update(self: *Verifier, data: []const u8) void {
self.h.update(data);
}pub fn verify(self: *Verifier) VerifyError!voidVerify that the signature is valid for the entire message.
self: *Verifierpub fn verify(self: *Verifier) VerifyError!void {
const ht = Curve.scalar.encoded_length;
const h_len = @max(Hash.digest_length, ht);
var h: [h_len]u8 = [_]u8{0} ** h_len;
self.h.final(h[h_len - Hash.digest_length .. h_len]);
const z = reduceToScalar(ht, h[0..ht].*);
if (z.isZero()) {
return error.SignatureVerificationFailed;
}
const s_inv = self.s.invert();
const v1 = z.mul(s_inv).toBytes(.little);
const v2 = self.r.mul(s_inv).toBytes(.little);
const v1g = try Curve.basePoint.mulPublic(v1, .little);
const v2pk = try self.public_key.p.mulPublic(v2, .little);
const vxs = v1g.add(v2pk).affineCoordinates().x.toBytes(.big);
const vr = reduceToScalar(Curve.Fe.encoded_length, vxs);
if (!self.r.equivalent(vr)) {
return error.SignatureVerificationFailed;
}
}pub const Verifier = struct {
h: Hash,
r: Curve.scalar.Scalar,
s: Curve.scalar.Scalar,
public_key: PublicKey,
pub const InitError = IdentityElementError || NonCanonicalError;
fn init(sig: Signature, public_key: PublicKey) InitError!Verifier {
const r = try Curve.scalar.Scalar.fromBytes(sig.r, .big);
const s = try Curve.scalar.Scalar.fromBytes(sig.s, .big);
if (r.isZero() or s.isZero()) return error.IdentityElement;
return Verifier{
.h = Hash.init(.{}),
.r = r,
.s = s,
.public_key = public_key,
};
}
/// Add new content to the message to be verified.
pub fn update(self: *Verifier, data: []const u8) void {
self.h.update(data);
}
pub const VerifyError = IdentityElementError || NonCanonicalError ||
SignatureVerificationError;
/// Verify that the signature is valid for the entire message.
pub fn verify(self: *Verifier) VerifyError!void {
const ht = Curve.scalar.encoded_length;
const h_len = @max(Hash.digest_length, ht);
var h: [h_len]u8 = [_]u8{0} ** h_len;
self.h.final(h[h_len - Hash.digest_length .. h_len]);
const z = reduceToScalar(ht, h[0..ht].*);
if (z.isZero()) {
return error.SignatureVerificationFailed;
}
const s_inv = self.s.invert();
const v1 = z.mul(s_inv).toBytes(.little);
const v2 = self.r.mul(s_inv).toBytes(.little);
const v1g = try Curve.basePoint.mulPublic(v1, .little);
const v2pk = try self.public_key.p.mulPublic(v2, .little);
const vxs = v1g.add(v2pk).affineCoordinates().x.toBytes(.big);
const vr = reduceToScalar(Curve.Fe.encoded_length, vxs);
if (!self.r.equivalent(vr)) {
return error.SignatureVerificationFailed;
}
}
}