Smart contracts
Deploy the Solidity you already know. SciChain runs a fully standard EVM, so every contract, framework, and pattern from the Ethereum ecosystem works unchanged — plus one superpower unique to SciChain: verifying post-quantum ML-DSA signatures directly on-chain.
EVM compatibility
SciChain executes at the Shanghai fork level. That means the PUSH0 opcode is available and modern Solidity compiles and runs without special flags — target solc 0.8.20+ and you are done. All of the standard EVM opcodes and the standard Ethereum precompiles (ecrecover, sha256, modexp, the BN256 curve operations, blake2f, and the rest) are present and behave exactly as they do on Ethereum mainnet.
Because the JSON-RPC surface is standard too, your existing toolchain needs no SciChain-specific plugins:
- Compilers & frameworks — Foundry, Hardhat, Truffle, Remix.
- Libraries — ethers.js, viem, web3.js, web3.py.
- Contract libraries — OpenZeppelin, Solmate, and other audited dependencies.
The only value you ever need to supply is the network endpoint (https://rpc.scimatic.net) and the chain ID (481).
If it runs on Ethereum, it runs on SciChain. The post-quantum features are strictly additive — a contract that never touches the ML-DSA precompile behaves identically to how it would on any Shanghai-level EVM chain.
Deploy with Foundry
Add SciChain as a named endpoint in foundry.toml so you can reference it by alias:
# foundry.toml
[rpc_endpoints]
scichain = "https://rpc.scimatic.net"
Then deploy a contract with forge create. SciChain's chain ID is 481, and forge reads it from the endpoint automatically:
# $PK is your deployer private key
export PK="0x<your-private-key>"
forge create \
--rpc-url https://rpc.scimatic.net \
--private-key "$PK" \
src/MyContract.sol:MyContract
# Or, using the named endpoint from foundry.toml:
forge create --rpc-url scichain --private-key "$PK" \
src/MyContract.sol:MyContract
Run tests and scripts against a fork of the live network in the same way, by passing --rpc-url https://rpc.scimatic.net to forge test or forge script.
Deploy with Hardhat
Register SciChain as a network in hardhat.config.js:
// hardhat.config.js
require("@nomicfoundation/hardhat-toolbox");
module.exports = {
solidity: "0.8.20",
networks: {
scichain: {
url: "https://rpc.scimatic.net",
chainId: 481,
accounts: [process.env.PRIVATE_KEY]
}
}
};
Deploy with your existing script by selecting the network:
npx hardhat run scripts/deploy.js --network scichain
A minimal deploy script looks exactly like it would on any other chain:
// scripts/deploy.js
const hre = require("hardhat");
async function main() {
const factory = await hre.ethers.getContractFactory("MyContract");
const contract = await factory.deploy();
await contract.waitForDeployment();
console.log("Deployed to:", await contract.getAddress());
}
main().catch((e) => { console.error(e); process.exitCode = 1; });
The ML-DSA precompile
SciChain adds a precompiled contract that verifies ML-DSA-44 (FIPS 204 / CRYSTALS-Dilithium2) signatures on-chain. It lives at a fixed address:
0x0000000000000000000000000000000000000134
Call it with staticcall, passing a single packed byte string of exactly 3764 bytes: the 32-byte message hash, followed by the 1312-byte ML-DSA-44 public key, followed by the 2420-byte signature.
Input layout
| Offset | Length | Field |
|---|---|---|
0 | 32 | Message hash (32-byte digest, e.g. keccak256) |
32 | 1312 | ML-DSA-44 public key |
1344 | 2420 | ML-DSA-44 signature |
Total input length: 32 + 1312 + 2420 = 3764 bytes.
Return semantics
| Result | Output | Meaning |
|---|---|---|
| Valid | 0x00…01 (32-byte word, left-padded 1) | The signature verifies against the public key and hash. |
| Invalid | Empty output (0 bytes) | The signature does not verify, or the input is malformed. |
Check both the call status and the output. Treat a signature as valid only when the staticcall succeeds and returns a 32-byte word equal to 1. An empty return means "invalid" — do not interpret it as success.
Solidity usage example
The following library wraps the precompile in a single safe helper, then uses it in a small verifier contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @title MLDSA — on-chain ML-DSA-44 (FIPS 204) signature verification
/// @notice Wraps the SciChain precompile at 0x…0134. Reverts nothing;
/// returns false on any invalid or malformed input.
library MLDSA {
address constant ML_DSA_VERIFY =
0x0000000000000000000000000000000000000134;
uint256 constant PUBKEY_LEN = 1312;
uint256 constant SIG_LEN = 2420;
function verifyMlDsa44(
bytes32 hash,
bytes memory pubKey,
bytes memory sig
) internal view returns (bool) {
require(pubKey.length == PUBKEY_LEN, "MLDSA: bad pubkey length");
require(sig.length == SIG_LEN, "MLDSA: bad signature length");
bytes memory input = abi.encodePacked(hash, pubKey, sig);
(bool ok, bytes memory out) = ML_DSA_VERIFY.staticcall(input);
// Valid iff the call succeeded and the precompile returned 0x..01.
return ok && out.length == 32 && out[31] == 0x01;
}
}
/// @notice Example: a message board that only accepts posts
/// authenticated with a quantum-safe ML-DSA-44 signature.
contract QuantumSafeBoard {
using MLDSA for bytes32;
event Posted(bytes32 indexed pubKeyHash, string message);
function post(
string calldata message,
bytes calldata pubKey,
bytes calldata sig
) external {
bytes32 digest = keccak256(bytes(message));
require(
MLDSA.verifyMlDsa44(digest, pubKey, sig),
"invalid ML-DSA signature"
);
emit Posted(keccak256(pubKey), message);
}
}
Verification, not signing. The precompile verifies a signature that was produced off-chain by an ML-DSA key. Private keys never touch the chain — you sign in your wallet or backend, then submit the public key and signature for the contract to check.
What you can build
On-chain ML-DSA verification unlocks contract patterns that stay secure even against a quantum adversary:
- Quantum-safe multisig — require M-of-N ML-DSA signatures to move funds or execute a call.
- Cross-chain & oracle bridges — accept messages only when signed by a post-quantum key held by the bridge committee.
- PQC identity & attestation — bind an ML-DSA public key to an on-chain identity and gate actions on quantum-safe proofs.
- Escrow & conditional release — release funds only upon presenting a valid ML-DSA signature over agreed terms.
Keep going See the exact JSON-RPC methods and PQC transaction fields in the JSON-RPC API, and learn how ML-DSA keys map to addresses in Transactions & addresses.