forked from crackedstudio/tikka
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcommitment.service.ts
More file actions
114 lines (98 loc) · 3.07 KB
/
Copy pathcommitment.service.ts
File metadata and controls
114 lines (98 loc) · 3.07 KB
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
import { OracleLoggerService } from '../logger/oracle-logger';
import { Injectable, Logger } from '@nestjs/common';
import * as crypto from 'crypto';
export interface Commitment {
raffleId: number;
secret: string;
nonce: string;
commitment: string;
committedAt: Date;
}
@Injectable()
export class CommitmentService {
constructor(private readonly logger: OracleLoggerService) {}
private readonly commitments = new Map<number, Commitment>();
/**
* Commit phase: Generate secret, nonce, and commitment hash
* @param raffleId The raffle ID
* @returns Commitment hash to submit to contract
*/
commit(raffleId: number): string {
// Generate cryptographically secure random values
const secret = crypto.randomBytes(32).toString('hex');
const nonce = crypto.randomBytes(16).toString('hex');
// Compute commitment = SHA-256(secret || nonce)
const commitment = this.computeCommitment(secret, nonce);
// Store for later reveal
this.commitments.set(raffleId, {
raffleId,
secret,
nonce,
commitment,
committedAt: new Date(),
});
this.logger.log(`Committed for raffle ${raffleId}: ${commitment}`);
return commitment;
}
/**
* Reveal phase: Retrieve secret and nonce for verification
* @param raffleId The raffle ID
* @returns Secret and nonce, or null if not found
*/
reveal(raffleId: number): { secret: string; nonce: string } | null {
const commitment = this.commitments.get(raffleId);
if (!commitment) {
this.logger.warn(`No commitment found for raffle ${raffleId}`);
return null;
}
this.logger.log(`Revealing for raffle ${raffleId}`);
// Return secret and nonce for contract verification
return {
secret: commitment.secret,
nonce: commitment.nonce,
};
}
/**
* Computes commitment hash from secret and nonce
* @param secret Random secret value
* @param nonce Random nonce value
* @returns SHA-256 hash of secret || nonce
*/
private computeCommitment(secret: string, nonce: string): string {
return crypto
.createHash('sha256')
.update(secret + nonce)
.digest('hex');
}
/**
* Verifies that a commitment matches the secret and nonce
* @param commitment The commitment hash
* @param secret The secret value
* @param nonce The nonce value
* @returns True if valid
*/
verifyCommitment(commitment: string, secret: string, nonce: string): boolean {
const computed = this.computeCommitment(secret, nonce);
return computed === commitment;
}
/**
* Clears commitment after successful reveal
* @param raffleId The raffle ID
*/
clearCommitment(raffleId: number): void {
this.commitments.delete(raffleId);
}
/**
* Gets commitment details (for debugging/monitoring)
* @param raffleId The raffle ID
*/
getCommitment(raffleId: number): Commitment | undefined {
return this.commitments.get(raffleId);
}
/**
* Gets all pending commitments
*/
getPendingCommitments(): Commitment[] {
return Array.from(this.commitments.values());
}
}