You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取ECDSA签名的固定长度字节表示(Python+cryptography.io)

固定长度ECDSA签名的实现方案

Great question! The variable length of DER-encoded ECDSA signatures happens because ASN.1 DER omits leading zeros from the integer values r and s—plus, if an integer's highest bit is set, DER adds an extra zero byte to avoid interpreting it as a negative number. This leads to signatures that can be 70, 71, or 72 bytes for 256-bit curves.

To get a fixed-length representation, the most common approach is to convert the DER signature into a concatenation of the r and s values, each padded to exactly 32 bytes (since 256 bits = 32 bytes). This gives you a consistent 64-byte signature. Here's how to do it with Python and the cryptography ecosystem:

Step 1: Install dependencies (if needed)

First, make sure you have asn1crypto installed (it's a reliable library for parsing ASN.1/DER data):

pip install asn1crypto cryptography

Step 2: Convert DER signature to fixed-length bytes

This function takes your DER-encoded signature and returns a 64-byte fixed-length version:

from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateKey
from cryptography.hazmat.primitives import hashes
import asn1crypto.core

def der_to_fixed_length(der_signature: bytes, curve_bit_length: int = 256) -> bytes:
    # Parse the DER signature into r and s integers
    signature_seq = asn1crypto.core.Sequence.load(der_signature)
    r = signature_seq[0].native
    s = signature_seq[1].native
    
    # Calculate the required byte length per value (256 bits = 32 bytes)
    per_value_byte_len = curve_bit_length // 8
    
    # Convert r and s to big-endian bytes, padding with leading zeros to reach fixed length
    r_bytes = r.to_bytes(per_value_byte_len, byteorder="big", signed=False)
    s_bytes = s.to_bytes(per_value_byte_len, byteorder="big", signed=False)
    
    # Concatenate to get the fixed-length signature
    return r_bytes + s_bytes

Step 3: Convert fixed-length back to DER for verification

If you need to verify the fixed-length signature later, you'll need to convert it back to DER format first. Here's how:

def fixed_length_to_der(fixed_signature: bytes, curve_bit_length: int = 256) -> bytes:
    per_value_byte_len = curve_bit_length // 8
    if len(fixed_signature) != per_value_byte_len * 2:
        raise ValueError(f"Fixed signature must be {per_value_byte_len * 2} bytes long")
    
    # Extract r and s from the fixed-length bytes
    r = int.from_bytes(fixed_signature[:per_value_byte_len], byteorder="big", signed=False)
    s = int.from_bytes(fixed_signature[per_value_byte_len:], byteorder="big", signed=False)
    
    # Build the ASN.1 sequence and dump it to DER
    signature_seq = asn1crypto.core.Sequence()
    signature_seq.append(asn1crypto.core.Integer(r))
    signature_seq.append(asn1crypto.core.Integer(s))
    return signature_seq.dump()

Example Usage

Here's how to tie it all together with your existing signing code:

# Assume you have your private key loaded as an EllipticCurvePrivateKey instance
private_key: EllipticCurvePrivateKey = ...
message = b"Your message to sign"

# Generate DER signature
der_sig = private_key.sign(message, ECDSA(hashes.SHA256()))

# Convert to fixed-length (64 bytes)
fixed_sig = der_to_fixed_length(der_sig)
print(f"Fixed signature length: {len(fixed_sig)} bytes")  # Output: 64

# Convert back to DER for verification
restored_der_sig = fixed_length_to_der(fixed_sig)

# Verify the restored signature (using your public key)
public_key = private_key.public_key()
public_key.verify(restored_der_sig, message, ECDSA(hashes.SHA256()))

This approach is widely used in systems like Bitcoin and other blockchain protocols, so it's a well-tested way to get consistent signature lengths.

内容的提问来源于stack exchange,提问作者jMyles

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:25:16