structstd.crypto.25519.ed25519.Ed25519.key_blinding[src]

Ed25519 signatures with key blinding.

Values

Constantblind_seed_length[src]

Length (in bytes) of a blinding seed.

Source Code

Source code
pub const blind_seed_length = 32

Source Code

Source code
pub const key_blinding = struct {
    /// Length (in bytes) of a blinding seed.
    pub const blind_seed_length = 32;

    /// A blind secret key.
    pub const BlindSecretKey = struct {
        prefix: [64]u8,
        blind_scalar: CompressedScalar,
        blind_public_key: BlindPublicKey,
    };

    /// A blind public key.
    pub const BlindPublicKey = struct {
        /// Public key equivalent, that can used for signature verification.
        key: PublicKey,

        /// Recover a public key from a blind version of it.
        pub fn unblind(blind_public_key: BlindPublicKey, blind_seed: [blind_seed_length]u8, ctx: []const u8) (IdentityElementError || NonCanonicalError || EncodingError || WeakPublicKeyError)!PublicKey {
            const blind_h = blindCtx(blind_seed, ctx);
            const inv_blind_factor = Scalar.fromBytes(blind_h[0..32].*).invert().toBytes();
            const pk_p = try (try Curve.fromBytes(blind_public_key.key.bytes)).mul(inv_blind_factor);
            return PublicKey.fromBytes(pk_p.toBytes());
        }
    };

    /// A blind key pair.
    pub const BlindKeyPair = struct {
        blind_public_key: BlindPublicKey,
        blind_secret_key: BlindSecretKey,

        /// Create an blind key pair from an existing key pair, a blinding seed and a context.
        pub fn init(key_pair: Ed25519.KeyPair, blind_seed: [blind_seed_length]u8, ctx: []const u8) (NonCanonicalError || IdentityElementError)!BlindKeyPair {
            var h: [Sha512.digest_length]u8 = undefined;
            Sha512.hash(&key_pair.secret_key.seed(), &h, .{});
            Curve.scalar.clamp(h[0..32]);
            const scalar = Curve.scalar.reduce(h[0..32].*);

            const blind_h = blindCtx(blind_seed, ctx);
            const blind_factor = Curve.scalar.reduce(blind_h[0..32].*);

            const blind_scalar = Curve.scalar.mul(scalar, blind_factor);
            const blind_public_key = BlindPublicKey{
                .key = try PublicKey.fromBytes((Curve.basePoint.mul(blind_scalar) catch return error.IdentityElement).toBytes()),
            };

            var prefix: [64]u8 = undefined;
            prefix[0..32].* = h[32..64].*;
            prefix[32..64].* = blind_h[32..64].*;

            const blind_secret_key = BlindSecretKey{
                .prefix = prefix,
                .blind_scalar = blind_scalar,
                .blind_public_key = blind_public_key,
            };
            return BlindKeyPair{
                .blind_public_key = blind_public_key,
                .blind_secret_key = blind_secret_key,
            };
        }

        /// Sign a message using a blind key pair, and optional random noise.
        /// Having noise creates non-standard, non-deterministic signatures,
        /// but has been proven to increase resilience against fault attacks.
        pub fn sign(key_pair: BlindKeyPair, msg: []const u8, noise: ?[noise_length]u8) (IdentityElementError || KeyMismatchError || NonCanonicalError || WeakPublicKeyError)!Signature {
            const scalar = key_pair.blind_secret_key.blind_scalar;
            const prefix = key_pair.blind_secret_key.prefix;

            return (try PublicKey.fromBytes(key_pair.blind_public_key.key.bytes))
                .computeNonceAndSign(msg, noise, scalar, &prefix);
        }
    };

    /// Compute a blind context from a blinding seed and a context.
    fn blindCtx(blind_seed: [blind_seed_length]u8, ctx: []const u8) [Sha512.digest_length]u8 {
        var blind_h: [Sha512.digest_length]u8 = undefined;
        var hx = Sha512.init(.{});
        hx.update(&blind_seed);
        hx.update(&[1]u8{0});
        hx.update(ctx);
        hx.final(&blind_h);
        return blind_h;
    }
}