nikivdev/code · error

invalid sealer secret length

Error message

invalid sealer secret length

What it means

get_sealer_id requires the decoded secret bytes to be exactly 32 bytes (an x25519 scalar key). If base58 decoding succeeds but the byte length differs, this error is thrown. The secret is structurally well-formed but encodes the wrong amount of key material.

Source

Thrown at src/sealer_crypto.rs:31

pub fn new_x25519_private_key() -> Vec<u8> {
    let mut bytes = [0u8; 32];
    SysRng
        .try_fill_bytes(&mut bytes)
        .expect("system RNG should provide x25519 key material");
    bytes.to_vec()
}

pub fn get_sealer_id(secret: &str) -> Result<String> {
    let secret_raw = secret
        .strip_prefix(SECRET_PREFIX)
        .ok_or_else(|| anyhow::anyhow!("invalid sealer secret prefix"))?;
    let private_bytes = bs58::decode(secret_raw)
        .into_vec()
        .map_err(|e| anyhow::anyhow!("invalid base58 sealer secret: {e}"))?;
    let bytes: [u8; 32] = private_bytes
        .as_slice()
        .try_into()
        .map_err(|_| anyhow::anyhow!("invalid sealer secret length"))?;

    let public = PublicKey::from(&StaticSecret::from(bytes)).to_bytes();
    Ok(format!(
        "{}{}",
        ID_PREFIX,
        bs58::encode(public).into_string()
    ))
}

pub fn seal(
    message: &[u8],
    sender_secret: &str,
    recipient_id: &str,
    nonce_material: &[u8],
) -> Result<Vec<u8>> {
    let sender_secret = decode_secret(sender_secret)?;
    let recipient_public = decode_id(recipient_id)?;
    let sender_key = StaticSecret::from(sender_secret);

View on GitHub (pinned to a747e741ae)

Solutions

  1. Use the complete 32-byte secret; re-copy the full value from its source.
  2. Regenerate the identity via create_sealer_identity / new_x25519_private_key and redistribute the new secret.
  3. If migrating keys from another tool, re-encode exactly 32 bytes as "sealerSecret_z" + base58.
  4. Verify length offline: base58-decode the body and check it is 32 bytes.

Example fix

// before: truncated secret decodes to 18 bytes
let id = get_sealer_id("sealerSecret_zShortKey")?;
// after: full 32-byte secret
let id = get_sealer_id("sealerSecret_zFullBase58Encoded32Bytes...")?;
Defensive patterns

Strategy: validation

Validate before calling

fn sealer_secret_is_32_bytes(s: &str) -> bool {
    s.strip_prefix("sealerSecret_z")
        .and_then(|body| bs58::decode(body).into_vec().ok())
        .map(|v| v.len() == 32)
        .unwrap_or(false)
}

Try / catch

match get_sealer_id(secret) {
    Err(e) if e.to_string().contains("invalid sealer secret length") => {
        eprintln!("secret decodes to wrong byte length; regenerate the identity");
        let (new_secret, _id) = create_sealer_identity()?;
        // persist and use new_secret
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling get_sealer_id with a "sealerSecret_z"-prefixed string whose base58 body decodes to fewer or more than 32 bytes — e.g. a truncated key or a key generated by a different scheme/curve.

Common situations: Truncated copy-paste, secrets generated by incompatible tooling (different key sizes), or concatenating two partial keys.

Related errors


AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01). Data as JSON: /api/errors/85d74a8bbcd0e50b. Report an issue: GitHub.