A Signer is used to incrementally compute a signature.
It can be obtained from a KeyPair, using the signer() function.
pub fn update(self: *Signer, data: []const u8) voidAdd new data to the message being signed.
self: *Signerdata: []const u8pub fn update(self: *Signer, data: []const u8) void {
self.h.update(data);
}pub fn finalize(self: *Signer) (IdentityElementError || NonCanonicalError)!SignatureCompute a signature over the entire message.
self: *Signerpub fn finalize(self: *Signer) (IdentityElementError || NonCanonicalError)!Signature {
const scalar_encoded_length = Curve.scalar.encoded_length;
const h_len = @max(Hash.digest_length, scalar_encoded_length);
var h: [h_len]u8 = [_]u8{0} ** h_len;
const h_slice = h[h_len - Hash.digest_length .. h_len];
self.h.final(h_slice);
std.debug.assert(h.len >= scalar_encoded_length);
const z = reduceToScalar(scalar_encoded_length, h[0..scalar_encoded_length].*);
const k = deterministicScalar(h_slice.*, self.secret_key.bytes, self.noise);
const p = try Curve.basePoint.mul(k.toBytes(.big), .big);
const xs = p.affineCoordinates().x.toBytes(.big);
const r = reduceToScalar(Curve.Fe.encoded_length, xs);
if (r.isZero()) return error.IdentityElement;
const k_inv = k.invert();
const zrs = z.add(r.mul(try Curve.scalar.Scalar.fromBytes(self.secret_key.bytes, .big)));
const s = k_inv.mul(zrs);
if (s.isZero()) return error.IdentityElement;
return Signature{ .r = r.toBytes(.big), .s = s.toBytes(.big) };
}pub const Signer = struct {
h: Hash,
secret_key: SecretKey,
noise: ?[noise_length]u8,
fn init(secret_key: SecretKey, noise: ?[noise_length]u8) !Signer {
return Signer{
.h = Hash.init(.{}),
.secret_key = secret_key,
.noise = noise,
};
}
/// Add new data to the message being signed.
pub fn update(self: *Signer, data: []const u8) void {
self.h.update(data);
}
/// Compute a signature over the entire message.
pub fn finalize(self: *Signer) (IdentityElementError || NonCanonicalError)!Signature {
const scalar_encoded_length = Curve.scalar.encoded_length;
const h_len = @max(Hash.digest_length, scalar_encoded_length);
var h: [h_len]u8 = [_]u8{0} ** h_len;
const h_slice = h[h_len - Hash.digest_length .. h_len];
self.h.final(h_slice);
std.debug.assert(h.len >= scalar_encoded_length);
const z = reduceToScalar(scalar_encoded_length, h[0..scalar_encoded_length].*);
const k = deterministicScalar(h_slice.*, self.secret_key.bytes, self.noise);
const p = try Curve.basePoint.mul(k.toBytes(.big), .big);
const xs = p.affineCoordinates().x.toBytes(.big);
const r = reduceToScalar(Curve.Fe.encoded_length, xs);
if (r.isZero()) return error.IdentityElement;
const k_inv = k.invert();
const zrs = z.add(r.mul(try Curve.scalar.Scalar.fromBytes(self.secret_key.bytes, .big)));
const s = k_inv.mul(zrs);
if (s.isZero()) return error.IdentityElement;
return Signature{ .r = r.toBytes(.big), .s = s.toBytes(.big) };
}
}