File size: 8,217 Bytes
863d0bc
 
 
 
 
 
7fbc6e8
863d0bc
c8a09fa
863d0bc
e9d8d8c
1d1169e
c12a1b5
4603a6e
6f74c05
0e26e1b
 
959f1f1
0e26e1b
4603a6e
 
 
863d0bc
04817f2
863d0bc
0e26e1b
 
 
 
 
e9d8d8c
 
8b2495b
30deb22
 
bf76a4c
c8a09fa
 
360d83b
959f1f1
c8a09fa
 
 
bf76a4c
0e26e1b
959f1f1
 
 
 
 
 
0e26e1b
6b7cb9a
 
959f1f1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6b7cb9a
959f1f1
6b7cb9a
 
bf76a4c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6b7cb9a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bf76a4c
10f42d2
 
 
 
 
 
4603a6e
bf76a4c
30deb22
 
 
10f42d2
120820f
 
30deb22
120820f
1ef6a10
120820f
 
863d0bc
120820f
e9d8d8c
4603a6e
 
863d0bc
 
 
 
4603a6e
 
 
 
 
 
 
 
 
 
 
 
 
 
863d0bc
bf76a4c
 
 
bdb583d
ba24c62
2a2bb1a
bdb583d
 
def47b4
 
 
bdb583d
def47b4
 
 
bdb583d
def47b4
 
bdb583d
 
def47b4
 
 
 
 
 
 
2d45c70
def47b4
bf76a4c
def47b4
bf76a4c
 
def47b4
bf76a4c
bdb583d
 
863d0bc
c8a09fa
 
4e24402
c8a09fa
 
 
 
 
6f74c05
c8a09fa
959f1f1
6a0c417
 
959f1f1
a78812e
959f1f1
 
 
6a0c417
 
959f1f1
6a0c417
959f1f1
 
 
 
6a0c417
c8a09fa
 
 
 
 
 
 
 
0e26e1b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c8a09fa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import hashlib
from solders.keypair import Keypair
from solders.pubkey import Pubkey
from solana.rpc.api import Client
from solders.transaction import Transaction
from solders.system_program import TransferParams, transfer
from solana.rpc.types import TxOpts
import base58
import hashlib
import os
#from helpers.mongodbconnection import provideClient
from fastapi.concurrency import run_in_threadpool
import pybase64
from web3 import Web3
import hexbytes





app = FastAPI()
solana_client = Client("https://devnet.helius-rpc.com/?api-key=4e833ada-d32c-48c5-b020-c11b2253f25b")

ETH_RPC_URL = "https://mainnet.infura.io/v3/7ad20d8703134068a4e4563f4a5a2279"
w3 = Web3(Web3.HTTPProvider(ETH_RPC_URL))



seed_text="shellinfo"
seed = hashlib.sha256(seed_text.encode()).digest()
SERVER_KEY = Keypair.from_seed(seed)



class TransactionPayload(BaseModel):
    signed_hex: str






class EthTransactionPayload(BaseModel):
    signed_hex: str 
    message: str      # The original message
    signature: str    # Base64 encoded signature
    public_key: str   # Base64 encoded public key





def verify_dc(message,signature,public_key):
    
    msg_bytes = message.encode('utf-8')
    sig_bytes = pybase64.b64decode(signature)
    pk_bytes =  pybase64.b64decode(public_key)

    with oqs.Signature("Dilithium5") as verifier:
            
            # 3. Perform Verification
        is_valid = verifier.verify(msg_bytes, sig_bytes, pk_bytes)
            
        if is_valid:
            return True
        else:
            return False

    

'''
CHAIN_LENGTH = 256
N = 32  # SHA256 output bytes

def verify_wots(signature, message, public_key):
    """
    signature: list[str] (base58 encoded, length 32)
    message: bytes
    public_key: list[str] (base58 encoded, length 32)
    """

    # Basic sanity checks
    if len(signature) != N or len(public_key) != N:
        print("Invalid lengths")
        return False

    # Hash the message
    msg_hash = hashlib.sha256(message).digest()

    for i in range(N):
        try:
            sig_i = base58.b58decode(signature[i])
            pk_i = base58.b58decode(public_key[i])
        except Exception as e:
            print(f"Base58 decode error at index {i}: {e}")
            return False

        check = sig_i

        # Walk forward in hash chain
        steps = CHAIN_LENGTH - msg_hash[i]

        for _ in range(steps):
            check = hashlib.sha256(check).digest()

        # Compare with public key element
        if check != pk_i:
            print(f"Mismatch at index {i}")
            return False

    return True



'''




CHAIN_LENGTH = 256
N_MESSAGE = 32  # Standard hash length
N_TOTAL = 34    # 32 (Message) + 2 (Checksum)

def verify_wots(signature, message, public_key):
    """
    signature: list[str] (base58 encoded, length 34)
    public_key: list[str] (base58 encoded, length 34)
    """
    if len(signature) != N_TOTAL or len(public_key) != N_TOTAL:
        print(f"Invalid lengths: expected {N_TOTAL}")
        return False

    # 1. Re-calculate the message hash
    msg_hash = hashlib.sha256(message).digest()

    # 2. Re-calculate the SAME Checksum as the client
    checksum = 0
    for byte in msg_hash:
        checksum += (255 - byte)
    
    # Convert checksum to 2 bytes
    cks_bytes = bytes([(checksum >> 8) & 0xff, checksum & 0xff])
    
    # 3. Combine them exactly like the client did
    combined = msg_hash + cks_bytes

    # 4. Verify all 34 chains
    for i in range(N_TOTAL):
        try:
            sig_i = base58.b58decode(signature[i])
            pk_i = base58.b58decode(public_key[i])
        except Exception as e:
            return False

        # Current revealed link
        check = sig_i

        # WALK FORWARD to the anchor (Public Key)
        # The client walked 'combined[i]' steps.
        # We walk the remaining steps to reach 256.
        steps = CHAIN_LENGTH - combined[i]

        for _ in range(steps):
            check = hashlib.sha256(check).digest()

        if check != pk_i:
            print(f"Mismatch at index {i}")
            return False

    return True






@app.get("/challenge")
def get_challenge():
    nonce = os.urandom(16)
    return {"nonce": base58.b58encode(nonce).decode()}


'''

@app.post("/relay-txn")
async def relay_txn(payload: dict):
    # 1. Verification Math
    message = base58.b58decode(payload["challange"])
    signature = payload["signature"]        # list[str]
    public_key = payload["anchorB58"]      # list[str]

    is_valid = verify_wots(signature, message, public_key)

    if not is_valid:
        return {"success": False, "error": "Invalid WOTS signature"}

    return {"success": True}
    
'''





@app.post("/relay-txn")
async def relay_txn(payload: dict):
    # Move the heavy math to a background thread
    is_valid = await run_in_threadpool(
        verify_wots, 
        payload["signature"], 
        base58.b58decode(payload["challange"]), 
        payload["anchorB58"]
    )
    
    if not is_valid:
        return {"success": False, "error": "Invalid WOTS signature"}
    return {"success": True}





@app.post("/sign-message")
async def sign_message(payload: dict):
    #message = bytes(payload["message"])

    # 1️⃣ verify quantum proof (same as your txn logic)
    #proof = base58.b58decode(payload["winternitz_proof"])
    #anchor = base58.b58decode(payload["anchor"])
    #lap = payload["lap"]

    #check = proof
    #for _ in range(256-lap):
     #   check = hashlib.sha256(check).digest()

    #if check != anchor:
     #   return {"success": False, "error": "Quantum auth failed"}


    #return {
     #   "success": True
    #}


    message = base58.b58decode(payload["message"])
    signature = payload["signature"]        # list[str]
    public_key = payload["anchorB58"]      # list[str]

    is_valid = verify_wots(signature, message, public_key)

    if not is_valid:
        return {"success": False, "error": "Invalid WOTS signature"}

    return {"success": True}




@app.post("/relay/broadcast/solana")
async def broadcast_transaction(payload: TransactionPayload):
    """
    Receives a pre-signed transaction, strips identifying headers and broadcasts to the Solana mainnet.
    """
    try:
        
        raw_tx = pybase64.b64decode(payload.signed_hex)

        
        
        response = solana_client.send_raw_transaction(raw_tx,opts=TxOpts(
            
                skip_preflight=True,
                preflight_commitment="processed"
            ))

        if not response.value:
            raise HTTPException(status_code=400, detail="Broadcast failed: No signature returned")

        return {
                "success": True,
                "signature": str(response.value),
                "status": "Broadcasted via Relay"
            }
       

    except Exception as e:
        print(f"Relay Error: {str(e)}")
        return {
            "success": False,
            "signature": '',
            "status": "Failed"
        }





@app.post("/relay/broadcast/ethereum")
async def broadcast_ethereum_transaction(payload: EthTransactionPayload):
    """
    Receives a signed ETH hex, strips headers, 
    and broadcasts to the Ethereum network.
    """
    try:
        # 1. Connection Check
        if not w3.is_connected():
            raise HTTPException(status_code=500, detail="Relayer lost connection to Ethereum Gateway")

    
        signed_tx = payload.signed_hex if payload.signed_hex.startswith("0x") else f"0x{payload.signed_hex}"

       
        tx_hash = w3.eth.send_raw_transaction(signed_tx)

        return {
            "success": True,
            "signature": tx_hash.hex(),
            "status": "Relayed to Ethereum Network"
        }

    except ValueError as ve:
        print(f"Validation Error: {str(ve)}")
        return {
            "success": False,
            "signature": tx_hash.hex(),
            "status": "Validation Error"
        }
    except Exception as e:
        print(f"Relay Error: {str(e)}")
        return {
            "success": False,
            "signature": tx_hash.hex(),
            "status": "Relay error"
        }