An ECDSA key pair.
Length (in bytes) of optional random bytes, for non-deterministic signatures.
pub const noise_length = Curve.scalar.encoded_lengthpub fn generateDeterministic(seed: [seed_length]u8) IdentityElementError!KeyPairDeterministically derive a key pair from a cryptograpically secure secret seed.
Except in tests, applications should generally call generate() instead of this function.
seed: [seed_length]u8pub fn generateDeterministic(seed: [seed_length]u8) IdentityElementError!KeyPair {
const h = [_]u8{0x00} ** Hash.digest_length;
const k0 = [_]u8{0x01} ** SecretKey.encoded_length;
const secret_key = deterministicScalar(h, k0, seed).toBytes(.big);
return fromSecretKey(SecretKey{ .bytes = secret_key });
}pub fn generate() KeyPairGenerate a new, random key pair.
pub fn generate() KeyPair {
var random_seed: [seed_length]u8 = undefined;
while (true) {
crypto.random.bytes(&random_seed);
return generateDeterministic(random_seed) catch {
@branchHint(.unlikely);
continue;
};
}
}pub fn fromSecretKey(secret_key: SecretKey) IdentityElementError!KeyPairReturn the public key corresponding to the secret key.
secret_key: SecretKeypub fn fromSecretKey(secret_key: SecretKey) IdentityElementError!KeyPair {
const public_key = try Curve.basePoint.mul(secret_key.bytes, .big);
return KeyPair{ .secret_key = secret_key, .public_key = PublicKey{ .p = public_key } };
}pub fn sign(key_pair: KeyPair, msg: []const u8, noise: ?[noise_length]u8) (IdentityElementError || NonCanonicalError)!SignatureSign a message using the key pair. The noise can be null in order to create deterministic signatures. If deterministic signatures are not required, the noise should be randomly generated instead. This helps defend against fault attacks.
pub fn sign(key_pair: KeyPair, msg: []const u8, noise: ?[noise_length]u8) (IdentityElementError || NonCanonicalError)!Signature {
var st = try key_pair.signer(noise);
st.update(msg);
return st.finalize();
}pub fn signer(key_pair: KeyPair, noise: ?[noise_length]u8) !SignerCreate a Signer, that can be used for incremental signature verification.
key_pair: KeyPairnoise: ?[noise_length]u8pub fn signer(key_pair: KeyPair, noise: ?[noise_length]u8) !Signer {
return Signer.init(key_pair.secret_key, noise);
}pub const KeyPair = struct {
/// Length (in bytes) of a seed required to create a key pair.
pub const seed_length = noise_length;
/// Public part.
public_key: PublicKey,
/// Secret scalar.
secret_key: SecretKey,
/// Deterministically derive a key pair from a cryptograpically secure secret seed.
///
/// Except in tests, applications should generally call `generate()` instead of this function.
pub fn generateDeterministic(seed: [seed_length]u8) IdentityElementError!KeyPair {
const h = [_]u8{0x00} ** Hash.digest_length;
const k0 = [_]u8{0x01} ** SecretKey.encoded_length;
const secret_key = deterministicScalar(h, k0, seed).toBytes(.big);
return fromSecretKey(SecretKey{ .bytes = secret_key });
}
/// Generate a new, random key pair.
pub fn generate() KeyPair {
var random_seed: [seed_length]u8 = undefined;
while (true) {
crypto.random.bytes(&random_seed);
return generateDeterministic(random_seed) catch {
@branchHint(.unlikely);
continue;
};
}
}
/// Return the public key corresponding to the secret key.
pub fn fromSecretKey(secret_key: SecretKey) IdentityElementError!KeyPair {
const public_key = try Curve.basePoint.mul(secret_key.bytes, .big);
return KeyPair{ .secret_key = secret_key, .public_key = PublicKey{ .p = public_key } };
}
/// Sign a message using the key pair.
/// The noise can be null in order to create deterministic signatures.
/// If deterministic signatures are not required, the noise should be randomly generated instead.
/// This helps defend against fault attacks.
pub fn sign(key_pair: KeyPair, msg: []const u8, noise: ?[noise_length]u8) (IdentityElementError || NonCanonicalError)!Signature {
var st = try key_pair.signer(noise);
st.update(msg);
return st.finalize();
}
/// Create a Signer, that can be used for incremental signature verification.
pub fn signer(key_pair: KeyPair, noise: ?[noise_length]u8) !Signer {
return Signer.init(key_pair.secret_key, noise);
}
}