Skip to main content

amadeus_node/consensus/
genesis.rs

1use crate::consensus::doms::attestation::Attestation;
2use crate::utils::{Hash, PublicKey, Signature};
3
4use crate::consensus::doms::entry::{Entry, EntryHeader};
5/// Translation of the Elixir EntryGenesis module.
6/// This module exposes static genesis values (signer, PoP, attestation, entry)
7/// and provides a deterministic builder + signer for the genesis entry.
8/// Some Elixir dependencies (BIC.Base.call_exit) are not implemented in Rust yet; see generate().
9
10#[derive(Debug, thiserror::Error)]
11pub enum Error {
12    #[error("unimplemented: {0}")]
13    Unimplemented(&'static str),
14    #[error(transparent)]
15    Bls(#[from] crate::utils::bls12_381::Error),
16}
17
18#[derive(Debug, Clone)]
19pub struct GenesisHeaderUnpacked {
20    pub slot: i64,
21    pub height: i64,
22    pub prev_slot: i64,
23    pub prev_hash: Vec<u8>,
24    pub dr: Hash,
25    pub vr: Vec<u8>,
26    pub signer: PublicKey,
27    pub root_tx: Hash,
28    pub root_validator: Hash,
29}
30
31#[derive(Debug, Clone)]
32pub struct GenesisEntry {
33    /// Header encoded as ETF binary (exact bytes from Elixir @genesis_entry.header)
34    pub header: Vec<u8>,
35    /// Entry signature (96 bytes, compressed G2, min_pk scheme)
36    pub signature: Signature,
37    /// Entry hash (32 bytes) as in Elixir @genesis_entry.hash
38    pub hash: Hash,
39    /// Unpacked header fields (for convenience)
40    pub header_unpacked: GenesisHeaderUnpacked,
41    /// Transactions list (empty for genesis)
42    pub txs: Vec<Vec<u8>>,
43}
44
45// --- Static constants copied from the original Elixir module comments ---
46// Signer pk (48 bytes in compressed G1)
47const SIGNER: PublicKey = PublicKey::new([
48    140, 27, 75, 245, 48, 112, 140, 244, 78, 114, 11, 45, 8, 201, 199, 184, 71, 69, 96, 112, 52, 204, 31, 56, 143, 115,
49    222, 87, 7, 185, 3, 168, 252, 90, 91, 114, 16, 244, 47, 228, 198, 82, 12, 130, 10, 126, 118, 193,
50]);
51
52// Proof of possession signature over pk in DST_POP (96 bytes)
53const POP: Signature = Signature::new([
54    175, 176, 86, 129, 118, 228, 182, 86, 225, 187, 236, 131, 170, 81, 121, 174, 164, 44, 71, 123, 136, 151, 170, 187,
55    43, 43, 211, 181, 163, 103, 93, 122, 11, 207, 92, 1, 190, 71, 46, 129, 210, 134, 62, 169, 152, 161, 189, 58, 18,
56    246, 6, 151, 128, 196, 116, 93, 20, 204, 153, 217, 81, 205, 1, 133, 65, 204, 177, 138, 74, 8, 104, 109, 214, 59,
57    245, 51, 47, 218, 15, 207, 190, 73, 40, 128, 108, 147, 250, 88, 241, 61, 129, 47, 189, 173, 118, 76,
58]);
59
60// Attestation constants
61const ATTESTATION_SIGNATURE: Signature = Signature::new([
62    151, 160, 206, 230, 190, 143, 68, 181, 248, 53, 105, 176, 56, 44, 82, 68, 252, 20, 61, 83, 33, 137, 74, 216, 149,
63    11, 242, 157, 237, 53, 139, 120, 202, 52, 30, 65, 9, 155, 243, 52, 53, 41, 236, 86, 235, 128, 52, 74, 12, 80, 187,
64    82, 174, 138, 121, 69, 159, 251, 97, 201, 238, 119, 163, 203, 122, 207, 179, 5, 178, 32, 145, 32, 183, 62, 184,
65    189, 136, 134, 80, 7, 193, 218, 133, 171, 154, 215, 219, 77, 33, 161, 152, 129, 142, 35, 9, 183,
66]);
67const ATTESTATION_MUTATIONS_HASH: Hash = Hash::new([
68    72, 67, 216, 106, 224, 102, 200, 77, 84, 86, 71, 38, 221, 89, 178, 87, 170, 13, 141, 117, 29, 103, 251, 177, 92,
69    143, 88, 218, 21, 177, 139, 196,
70]);
71const ATTESTATION_ENTRY_HASH: Hash = Hash::new([
72    250, 154, 199, 170, 114, 250, 155, 84, 2, 215, 37, 236, 138, 98, 19, 87, 19, 163, 21, 138, 131, 205, 205, 189, 176,
73    217, 5, 112, 225, 13, 15, 217,
74]);
75
76// Genesis entry constants
77const GENESIS_SIGNATURE: Signature = Signature::new([
78    179, 146, 253, 87, 173, 166, 85, 68, 73, 181, 204, 201, 40, 101, 234, 64, 243, 202, 202, 35, 214, 166, 101, 4, 82,
79    168, 131, 119, 230, 126, 98, 253, 153, 117, 239, 112, 203, 145, 116, 17, 53, 235, 113, 23, 73, 26, 91, 171, 11, 28,
80    244, 153, 250, 238, 23, 205, 114, 124, 195, 112, 171, 200, 45, 108, 129, 26, 219, 122, 24, 43, 162, 187, 120, 106,
81    116, 236, 25, 140, 129, 215, 83, 78, 184, 11, 9, 108, 22, 132, 47, 26, 250, 246, 119, 252, 81, 91,
82]);
83const GENESIS_HASH: Hash = ATTESTATION_ENTRY_HASH; // same as in attestation section
84
85const GENESIS_HEADER_UNPACKED_DR: Hash = Hash::new([
86    85, 13, 37, 23, 114, 150, 131, 140, 136, 174, 76, 72, 122, 45, 180, 165, 94, 229, 194, 27, 2, 87, 249, 159, 121,
87    177, 233, 167, 179, 0, 217, 219,
88]);
89const GENESIS_HEADER_UNPACKED_VR: Signature = Signature::new([
90    181, 221, 57, 62, 159, 101, 228, 75, 242, 59, 58, 92, 179, 234, 71, 120, 2, 232, 181, 156, 102, 142, 148, 152, 180,
91    116, 198, 158, 94, 152, 24, 27, 115, 224, 103, 169, 12, 237, 98, 44, 113, 237, 198, 210, 218, 83, 162, 181, 5, 65,
92    253, 232, 57, 140, 196, 121, 187, 108, 46, 68, 159, 45, 220, 62, 254, 201, 44, 135, 201, 126, 206, 74, 140, 239,
93    177, 95, 169, 40, 181, 104, 167, 84, 50, 207, 85, 35, 42, 10, 36, 196, 9, 13, 156, 79, 186, 117,
94]);
95const GENESIS_HEADER_UNPACKED_ROOT_TX: Hash = Hash::new([
96    175, 19, 73, 185, 245, 249, 161, 166, 160, 64, 77, 234, 54, 220, 201, 73, 155, 203, 37, 201, 173, 193, 18, 183,
97    204, 154, 147, 202, 228, 31, 50, 98,
98]);
99const GENESIS_HEADER_UNPACKED_ROOT_VALIDATOR: Hash = Hash::new([0u8; 32]);
100
101// --- Public API ---
102
103pub fn signer() -> PublicKey {
104    SIGNER
105}
106
107pub fn pop() -> Signature {
108    POP
109}
110
111pub fn attestation() -> Attestation {
112    Attestation {
113        entry_hash: ATTESTATION_ENTRY_HASH,
114        mutations_hash: ATTESTATION_MUTATIONS_HASH,
115        signer: SIGNER,
116        signature: ATTESTATION_SIGNATURE,
117    }
118}
119
120pub fn get_gen_entry() -> Entry {
121    let header = EntryHeader {
122        slot: 0,
123        height: 0,
124        prev_slot: -1,
125        prev_hash: Hash::from([0; 32]),
126        dr: GENESIS_HEADER_UNPACKED_DR,
127        vr: GENESIS_HEADER_UNPACKED_VR,
128        signer: SIGNER,
129        root_tx: GENESIS_HEADER_UNPACKED_ROOT_TX,
130        root_validator: GENESIS_HEADER_UNPACKED_ROOT_VALIDATOR,
131    };
132
133    Entry { header, signature: GENESIS_SIGNATURE, hash: GENESIS_HASH, mask: None, txs: vec![] }
134}
135
136/// Generate the same tuple as the Elixir generate/0 would: {entry_signed, attestation, pop}.
137/// NOTE: at the moment, some required building blocks are not implemented in Rust:
138/// - Entry.sign/1 and pack/unpack equivalents are not present in consensus::entry
139/// - BIC.Base.call_exit/1 is not implemented (see bic::base::call_exit_todo)
140/// - Trainer keys source is unspecified (Elixir uses Application.fetch_env!)
141///
142/// Because deterministic ETF encoding order affects signatures/hashes, we keep the static values above.
143/// This function returns an explicit Unimplemented error with targeted questions for the integrator.
144pub fn generate() -> Result<(GenesisEntry, Attestation, Signature), Error> {
145    Err(Error::Unimplemented(
146        "Entry genesis generation requires: (1) source of trainer_pk/sk in Rust (env names?), \
147         (2) Entry signing/packing API over ETF header (consensus::entry), and (3) BIC.Base.call_exit mutations. \
148         Please advise on keys sourcing and whether to hardcode provided constants or implement full deterministic build.",
149    ))
150}