{"record":{"id":"f39848bb62358f48","repo":"canopy-network/canopy","slug":"all-zero-shared-secret","errorCode":null,"errorMessage":"all zero shared secret","messagePattern":"all zero shared secret","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/crypto/ecdh.go","lineNumber":34,"sourceCode":"// SharedSecret function takes ed25519 public and private keys, converts them to Curve25519-compatible keys,\n// and performs a Diffie-Hellman-style key exchange with X25519 - meaning both peers compute exact pseudorandom\n// bytes from their peersPublicKey and their local private key without transmitting the secret over the wire\nfunc SharedSecret(peerPublicKey, private []byte) ([]byte, error) {\n\t// convert the peer public key to Curve 25519\n\txPub, err := Ed25519PublicKeyToCurve25519(peerPublicKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// convert local private key to Curve 25519\n\txPriv := Ed25519PrivateKeyToCurve25519(private)\n\t// generate a secret from the\n\tsecret, err := curve25519.X25519(xPriv, xPub)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\t// ensure the secret isn't an 'all-zero' byte array as this would be a weak or invalid key agreement\n\tif subtle.ConstantTimeCompare(secret[:], new([32]byte)[:]) == 1 {\n\t\treturn nil, fmt.Errorf(\"all zero shared secret\")\n\t}\n\t// return the diffie hellman secret\n\treturn secret, nil\n}\n\n// Ed25519PrivateKeyToCurve25519 hashes the Ed25519 private key seed and extracts the first 32 bytes to form a\n// Curve25519 scalar, which is compatible with Curve25519 operations\n// This conversion allows the use of a single cryptographic key pair Ed25519 for both signing and key exchange\nfunc Ed25519PrivateKeyToCurve25519(pk ed25519.PrivateKey) []byte {\n\th := sha512.New()\n\th.Write(pk.Seed())\n\tout := h.Sum(nil)\n\treturn out[:curve25519.ScalarSize]\n}\n\n// Ed25519PublicKeyToCurve25519 interprets the Ed25519 public key as a point on the Edwards25519 curve and converts\n// it to a Curve25519 public key in Montgomery form, suitable for X25519 encryption\n// This conversion allows the use of a single cryptographic key pair Ed25519 for both signing and key exchange","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/canopy-network/canopy/blob/ee8197d91dd410f6592cb650a94c925ee6dc8bad/lib/crypto/ecdh.go#L16-L52","documentation":"Raised in SharedSecret when the X25519 Diffie-Hellman computation yields an all-zero shared secret. This happens with degenerate key inputs (e.g. a low-order or improperly converted Curve25519 public key) and is rejected because an all-zero secret provides zero cryptographic security — it would make encryption trivially breakable.","triggerScenarios":"Thrown at lib/crypto/ecdh.go:34 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Verify the peer's ed25519 public key is valid and correctly converted to Curve25519 before the exchange.","Discard the session and have the peer regenerate its keypair; a zero output indicates a bad peer key.","Clamp private keys as required by X25519 and confirm Ed25519PrivateKeyToCurve25519 conversion is correct."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"ee8197d91dd410f6592cb650a94c925ee6dc8bad","analyzedAt":"2026-09-06T09:30:15.973Z","contentChangedAt":"2026-09-06T09:30:15.973Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}