mirror of
https://github.com/luxfi/relay.git
synced 2026-10-30 15:20:05 +00:00
- SignedReceipt now carries an explicit Scheme tag (wire-stable enum 0x01=ml-dsa-65, 0x02=ed25519) so the verifier dispatches deterministically. - RegisterNodePublicKey(nodeID, scheme, pub) replaces the Ed25519-only signature. Registration accepts both schemes; verification is the gate (single call to profile.Verify). - verifyReceiptSignature: ONE call site, ONE function — profile.Verify with the active vm.policy. No more direct ed25519.Verify in the VM. - vm.Config.LegacyClassicalEnabled wires the chain-level toggle into profile.Policy. - Soundness fix: previously, an unregistered NodeID caused verify to "log and accept" — a latent forgery path. It now returns errInvalidSignature explicitly. 4 e2e tests cover the PQ-default path, strict-PQ classical refusal, legacy opt-in, and the unregistered-node refuse. 2 fuzz targets (FuzzReceiptDecode, FuzzMessageDecode) survive ≥50k execs with no panics.
55 lines
1.3 KiB
Go
55 lines
1.3 KiB
Go
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package vm
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
)
|
|
|
|
// FuzzReceiptDecode feeds the JSON receipt decoder arbitrary bytes to confirm
|
|
// it never panics — the decoder is at the trust boundary between R-Chain RPC
|
|
// callers and the receipt registry.
|
|
func FuzzReceiptDecode(f *testing.F) {
|
|
// Seed with a known-good receipt shape.
|
|
good := &SignedReceipt{
|
|
Scheme: 0x01,
|
|
Timestamp: 1,
|
|
Signature: []byte("seed-sig"),
|
|
}
|
|
if b, err := json.Marshal(good); err == nil {
|
|
f.Add(b)
|
|
}
|
|
// Edge cases.
|
|
f.Add([]byte(`{}`))
|
|
f.Add([]byte(`null`))
|
|
f.Add([]byte(`{"scheme":255,"signature":null}`))
|
|
f.Add([]byte(`{"scheme":1,"timestamp":-1}`))
|
|
|
|
f.Fuzz(func(t *testing.T, data []byte) {
|
|
var r SignedReceipt
|
|
_ = json.Unmarshal(data, &r) // must not panic
|
|
})
|
|
}
|
|
|
|
// FuzzMessageDecode does the same for the cross-chain Message envelope.
|
|
func FuzzMessageDecode(f *testing.F) {
|
|
good := &Message{
|
|
Sequence: 1,
|
|
State: MessagePending,
|
|
Payload: []byte("x"),
|
|
}
|
|
if b, err := json.Marshal(good); err == nil {
|
|
f.Add(b)
|
|
}
|
|
f.Add([]byte(`{}`))
|
|
f.Add([]byte(`null`))
|
|
f.Add([]byte(`{"sequence":-1}`))
|
|
|
|
f.Fuzz(func(t *testing.T, data []byte) {
|
|
var m Message
|
|
_ = json.Unmarshal(data, &m) // must not panic
|
|
})
|
|
}
|