Crate fn_dsa

Source
Expand description

§FN-DSA implementation

This crate is really a wrapper for the fn-dsa-kgen, fn-dsa-sign and fn-dsa-vrfy crates that implement the various elements of the FN-DSA signature algorithm. All the relevant types, functions and constants are re-exported here. Users of this implementation only need to import this crate; the division into sub-crates is meant to help with specialized situations where code footprint reduction is important (typically, embedded systems that only need to verify signatures, but not generate keys or signatures).

§WARNING

The FN-DSA standard is currently being drafted, but no version has been published yet. When published, it may differ from the exact scheme implemented in this crate, in particular with regard to key encodings, message pre-hashing, and domain separation. Key pairs generated with this crate MAY fail to be interoperable with the final FN-DSA standard. This implementation is expected to be adjusted to the FN-DSA standard when published (before the 1.0 version release).

§Implementation notes

The whole code is written in pure Rust and is compatible with no_std. It has no external dependencies except rand_core and zeroize (unit tests use a few extra crates).

On x86 (both 32-bit and 64-bit), AVX2 opcodes are automatically used for faster operations if their support is detected at runtime. No special compilation flag nor extra runtime check is needed for that; the compiled code remains compatible with plain non-AVX2-aware CPUs.

On 64-bit x86 (x86_64) and ARMv8 (aarch64, arm64ec), native (hardware) floating-point support is used, since in both these cases the architecture ABI mandates a strict IEEE-754 unit and can more or less be assumed to operate in constant-time for non-exceptional inputs. This makes signature generation much faster on these platforms (on x86_64, this furthermore combines with AVX2 optimizations if available in the current CPU). On other platforms, a portable emulation of floating-point operations is used (this emulation makes a best effort at operating in constant-time, though some recent compiler optimizations might introduce variable-time operations). Key pair generation and signature verification do not use floating-point operations at all.

The key pair generation implementation is a translation of the ntrugen code, which is faster than the originally submitted Falcon code. The signature generation engine follows the steps of the sign_dyn operations from the original falcon code (indeed, an internal unit tests checks that the sampler returns the same values for the same inputs). Achieved performance on x86_64 is very close to that offered by the C code (signature verification performance is even better).

§Example usage

use rand_core::OsRng;
use fn_dsa::{
    sign_key_size, vrfy_key_size, signature_size, FN_DSA_LOGN_512,
    KeyPairGenerator, KeyPairGeneratorStandard,
    SigningKey, SigningKeyStandard,
    VerifyingKey, VerifyingKeyStandard,
    DOMAIN_NONE, HASH_ID_RAW,
};
 
// Generate key pair.
let mut kg = KeyPairGeneratorStandard::default();
let mut sign_key = [0u8; sign_key_size(FN_DSA_LOGN_512)];
let mut vrfy_key = [0u8; vrfy_key_size(FN_DSA_LOGN_512)];
kg.keygen(FN_DSA_LOGN_512, &mut OsRng, &mut sign_key, &mut vrfy_key);
 
// Sign a message with the signing key.
let mut sk = SigningKeyStandard::decode(encoded_signing_key)?;
let mut sig = vec![0u8; signature_size(sk.get_logn())];
sk.sign(&mut OsRng, &DOMAIN_NONE, &HASH_ID_RAW, b"message", &mut sig);
 
// Verify a signature with the verifying key.
match VerifyingKeyStandard::decode(encoded_verifying_key) {
    Some(vk) => {
        if vk.verify(sig, &DOMAIN_NONE, &HASH_ID_RAW, b"message") {
            // signature is valid
        } else {
            // signature is not valid
        }
    }
    _ => {
        // could not decode verifying key
    }
}

Structs§

  • When a message is signed or verified, it is accompanied with a domain separation context, which is an arbitrary sequence of bytes of length at most 255. Such a context is wrapped in a DomainContext structure.
  • The message for which a signature is to be generated or verified is pre-hashed by the caller and provided as a hash value along with an identifier of the used hash function. The identifier is normally an encoded ASN.1 OID. A special identifier is used for “raw” messages (i.e. not pre-hashed at all); it uses a single byte of value 0x00.
  • Key pair generator for degrees (logn) 9 to 9 only.
  • Key pair generator for degrees (logn) 10 to 10 only.
  • Key pair generator for degrees (logn) 9 to 10 only.
  • Key pair generator for degrees (logn) 2 to 8 only.
  • Error type of random number generators
  • SHAKE implementation.
  • Signature generator for degrees (logn) 9 to 9 only.
  • Signature generator for degrees (logn) 10 to 10 only.
  • Signature generator for degrees (logn) 9 to 10 only.
  • Signature generator for degrees (logn) 2 to 8 only.
  • Signature verifier for degrees (logn) 9 to 9 only.
  • Signature verifier for degrees (logn) 10 to 10 only.
  • Signature verifier for degrees (logn) 9 to 10 only.
  • Signature verifier for degrees (logn) 2 to 8 only.

Constants§

Traits§

Functions§

  • Get the size (in bytes) of a signing key for the provided degree (degree is n = 2^logn, with 2 <= logn <= 10).
  • Get the size (in bytes) of a signature for the provided degree (degree is n = 2^logn, with 2 <= logn <= 10).
  • Get the size (in bytes) of a verifying key for the provided degree (degree is n = 2^logn, with 2 <= logn <= 10).

Type Aliases§

  • Type specialization for SHAKE128.
  • Type specialization for SHAKE256.