Expand description
§paralock-core
The protocol core of Paralock: trustless swaps between ZEC and stablecoins on EVM chains. A lock on Zcash and a lock on the EVM chain share one secret, so either both sides settle or both refund.
This crate is the single implementation behind every Paralock SDK. It is pure and synchronous: no I/O, no
clocks, no network, no async. Randomness is injected by the caller as a rand_core::CryptoRngCore (an
OsRng convenience is available with the default std feature), consensus branch ids and the current time are
always inputs, and every parser of untrusted data returns a Result instead of panicking.
It is a byte-for-byte port of the TypeScript reference (@paralock/zcash, @paralock/adaptor,
@paralock/evm, @paralock/sdk): scripts, addresses, transactions, signature hashes, txids, escrow ids, claim
digests, adaptor pre-signatures and JSON messages are identical, and the test suite checks them against shared
cross-language vectors.
§Modules
zcash: transparent addresses, keys, scripts, the HTLC and 2-of-2 multisig templates, v5 transactions, ZIP 244 txids and signature hashes, ZIP 317 fees and the transaction builders.adaptor: ECDSA adaptor signatures on secp256k1 with Chaum–Pedersen DLEQ proofs (private mode).evm:ParalockHTLC/ParalockAdaptorEscrowswap ids, claim digests, hashlocks, recovery ids and EVM addresses.protocol: the swap wire messages (serde, identical JSON, decoded through strict validating parsers), the composite safety checks of both parties, the timeout policy, pricing and privacy helpers.keys: secp256k1 private and public keys and 32-byte secrets shared by all of the above.
§Example: an HTLC and its claim
use paralock_core::keys::{KeyPair, Secret};
use paralock_core::zcash::{
build_htlc_claim, Htlc, HtlcParams, Network, TransparentAddress, TxOptions, Txid, Utxo,
};
let mut rng = paralock_core::OsRng;
let maker = KeyPair::random(&mut rng);
let taker = KeyPair::random(&mut rng);
let secret = Secret::random(&mut rng);
// The taker locks ZEC that the maker can claim with the secret, or the taker can refund at height 1_000.
let htlc = Htlc::new(
HtlcParams {
hashlock: secret.hashlock(),
claim_pubkey: maker.public_key(),
refund_pubkey: taker.public_key(),
refund_height: 1_000,
},
Network::Regtest,
)?;
assert!(htlc.address().starts_with("t2"));
// Once funded, the maker claims with the secret. The consensus branch id comes from the node.
let utxo = Utxo {
txid: Txid::from_display_hex(&"11".repeat(32))?,
vout: 0,
value: 100_000_000,
script_pubkey: htlc.script_pubkey().to_vec(),
};
let to = TransparentAddress::p2pkh(&maker.public_key(), Network::Regtest);
let options = TxOptions::new(0x37a5_165b, Network::Regtest);
let claim = build_htlc_claim(&htlc, &utxo, &maker, &secret, &to, &options)?;
assert_eq!(claim.fee, 10_000);§Safety
The crate forbids unsafe code. Private keys, HTLC preimages and adaptor secrets are zeroized on drop and compared
in constant time. Signatures are low-S everywhere, every adaptor pre-signature uses a fresh hedged nonce, and the
redeem-script parsers accept only the exact Paralock templates. Values the builders and checks rely on are
validated when they are constructed (keys::KeyPair, protocol::TimeoutPolicy, zcash::Htlc,
adaptor::VerifiedPreSignature, …), so they can’t be assembled inconsistently.
Use the composite checks of protocol (verify_*, complete_escrow_claim) rather than the building blocks:
they check everything a protocol step requires against the stored messages. A claim that reverts still reveals
the secret (the preimage or the completed adaptor signature is in its calldata): re-check the lock right before
claiming and simulate the claim (eth_call) before broadcasting it.
This code is experimental; it has been through one security review, whose findings are fixed in 0.1.0 (see
CHANGELOG.md), but it has not had a formal audit. The Zcash leg in htlc mode is transparent.
Modules§
- adaptor
- ECDSA adaptor signatures on secp256k1, for scriptless atomic swaps (a port of
@paralock/adaptor). - encoding
- Byte encodings shared by the whole crate: hex (with or without
0x), Bitcoin-style CompactSize lengths and a bounds-checked little-endianReader. - evm
- The EVM leg:
ParalockHTLCandParalockAdaptorEscrowswap structs, their ids and commitments (keccak256(abi.encode(swap))), the adaptor escrow’s claim digest, hashlocks, canonical(v, r, s)claim signatures and EVM addresses. A port of@paralock/evm’s pure helpers with hand-written ABI encoding (every field is a static 32-byte word). - keys
- secp256k1 keys, ECDSA signatures and 32-byte secrets.
- protocol
- The swap protocol: wire messages, validation, timeouts, pricing and privacy helpers (a port of
@paralock/sdk’stypes.ts,adaptor-protocol.ts,validation.ts,policy.ts,pricing.ts,privacy.ts,secret.tsand the error codes oferrors.ts). - zcash
- Zcash: transparent addresses, scripts, the Paralock HTLC and 2-of-2 templates, v5 transactions, ZIP 244 and
ZIP 317, and the transaction builders. A port of
@paralock/zcash(plus the ZIP 244 shielded digests of@paralock/lightwalletd), byte for byte.
Structs§
- OsRng
- The operating system’s random number generator (
rand_core::OsRng). Requires thegetrandomfeature (on by default throughstd). A random number generator that retrieves randomness from the operating system.
Enums§
- Error
- Any error this crate returns. Each module also has its own precise error type, which converts into this one.
Traits§
- Crypto
Rng - A marker trait used to indicate that an
RngCoreorBlockRngCoreimplementation is supposed to be cryptographically secure. - Crypto
RngCore - An extension trait that is automatically implemented for any type
implementing
RngCoreandCryptoRng. - RngCore
- The core of a random number generator.