-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathdomain.rs
More file actions
172 lines (148 loc) · 6.03 KB
/
Copy pathdomain.rs
File metadata and controls
172 lines (148 loc) · 6.03 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
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
use miden_crypto::{Felt, Word};
// Helper function to encode a single character to its numeric representation
pub fn encode_char(chr: char) -> Option<u8> {
match chr {
'a' => Some(1), 'b' => Some(2), 'c' => Some(3), 'd' => Some(4),
'e' => Some(5), 'f' => Some(6), 'g' => Some(7), 'h' => Some(8),
'i' => Some(9), 'j' => Some(10), 'k' => Some(11), 'l' => Some(12),
'm' => Some(13), 'n' => Some(14), 'o' => Some(15), 'p' => Some(16),
'q' => Some(17), 'r' => Some(18), 's' => Some(19), 't' => Some(20),
'u' => Some(21), 'v' => Some(22), 'w' => Some(23), 'x' => Some(24),
'y' => Some(25), 'z' => Some(26),
'0' => Some(27), '1' => Some(28), '2' => Some(29), '3' => Some(30),
'4' => Some(31), '5' => Some(32), '6' => Some(33), '7' => Some(34),
'8' => Some(35), '9' => Some(36),
_ => None,
}
}
// Helper function to decode a numeric value back to a character
pub fn decode_char(encoded: u8) -> Option<char> {
match encoded {
1 => Some('a'), 2 => Some('b'), 3 => Some('c'), 4 => Some('d'),
5 => Some('e'), 6 => Some('f'), 7 => Some('g'), 8 => Some('h'),
9 => Some('i'), 10 => Some('j'), 11 => Some('k'), 12 => Some('l'),
13 => Some('m'), 14 => Some('n'), 15 => Some('o'), 16 => Some('p'),
17 => Some('q'), 18 => Some('r'), 19 => Some('s'), 20 => Some('t'),
21 => Some('u'), 22 => Some('v'), 23 => Some('w'), 24 => Some('x'),
25 => Some('y'), 26 => Some('z'),
27 => Some('0'), 28 => Some('1'), 29 => Some('2'), 30 => Some('3'),
31 => Some('4'), 32 => Some('5'), 33 => Some('6'), 34 => Some('7'),
35 => Some('8'), 36 => Some('9'),
_ => None,
}
}
// Name encoding decoding
// 7 bits per felt
// Total 4 felts
// Felts in word must not be reversed in storage
// So we have to reverse here
// [P4, P3, P2, P1] -> on MASM [P1, P2, P3, P4]
pub fn encode_domain(domain: String) -> Word {
// Validate length: must be > 0 and <= 20
let len = domain.len();
assert!(len > 0, "Domain name must have at least 1 character");
assert!(len <= 20, "Domain name must be at most 20 characters");
// Encode each character and store in a vector
let mut encoded_chars: Vec<u8> = Vec::new();
for c in domain.chars() {
let char_code = encode_char(c)
.expect(&format!("Invalid character '{}' in domain name", c));
encoded_chars.push(char_code);
}
// Pack characters into Felts (7 characters per Felt, 8 bits each)
// First 7 characters go into felt3, next 7 into felt2, next 6 into felt1
let mut felt1: u64 = 0;
let mut felt2: u64 = 0;
let mut felt3: u64 = 0;
for (i, &char_code) in encoded_chars.iter().enumerate() {
let bit_shift = (i % 7) * 8;
if i < 7 {
// First 7 characters go into felt3
felt3 |= (char_code as u64) << bit_shift;
} else if i < 14 {
// Next 7 characters go into felt2
felt2 |= (char_code as u64) << bit_shift;
} else {
// Remaining characters go into felt1
felt1 |= (char_code as u64) << bit_shift;
}
}
// Format: [felt1, felt2, felt3, length]
// This is reversed for MASM storage (becomes [length, felt3, felt2, felt1] on stack)
Word::new([
Felt::new(felt1),
Felt::new(felt2),
Felt::new(felt3),
Felt::new(len as u64),
])
}
pub fn encode_domain_as_felts(domain: String) -> [Felt;4] {
let encoded_domain = encode_domain(domain).to_vec();
[encoded_domain[0], encoded_domain[1], encoded_domain[2], encoded_domain[3]]
}
pub fn unsafe_encode_domain(domain: String) -> Word {
// Validate length: must be > 0 and <= 20
let len = domain.len();
// Encode each character and store in a vector
let mut encoded_chars: Vec<u8> = Vec::new();
for c in domain.chars() {
let char_code = encode_char(c)
.expect(&format!("Invalid character '{}' in domain name", c));
encoded_chars.push(char_code);
}
// Pack characters into Felts (7 characters per Felt, 8 bits each)
// First 7 characters go into felt3, next 7 into felt2, next 6 into felt1
let mut felt1: u64 = 0;
let mut felt2: u64 = 0;
let mut felt3: u64 = 0;
for (i, &char_code) in encoded_chars.iter().enumerate() {
let bit_shift = (i % 7) * 8;
if i < 7 {
// First 7 characters go into felt3
felt3 |= (char_code as u64) << bit_shift;
} else if i < 14 {
// Next 7 characters go into felt2
felt2 |= (char_code as u64) << bit_shift;
} else {
// Remaining characters go into felt1
felt1 |= (char_code as u64) << bit_shift;
}
}
// Format: [felt1, felt2, felt3, length]
// This is reversed for MASM storage (becomes [length, felt3, felt2, felt1] on stack)
Word::new([
Felt::new(felt1),
Felt::new(felt2),
Felt::new(felt3),
Felt::new(len as u64),
])
}
pub fn decode_domain(encoded_domain: Word) -> String {
let felts = encoded_domain.to_vec();
// Extract length from the 4th felt
let length = felts[3].as_int() as usize;
// Extract the three data felts
let felt1 = felts[0].as_int();
let felt2 = felts[1].as_int();
let felt3 = felts[2].as_int();
let mut decoded_chars: Vec<char> = Vec::new();
// Decode characters from each felt (7 characters per felt, 8 bits each)
for i in 0..length {
let char_code = if i < 7 {
// First 7 characters from felt3
((felt3 >> (i * 8)) & 0xFF) as u8
} else if i < 14 {
// Next 7 characters from felt2
((felt2 >> ((i - 7) * 8)) & 0xFF) as u8
} else {
// Remaining characters from felt1
((felt1 >> ((i - 14) * 8)) & 0xFF) as u8
};
if let Some(chr) = decode_char(char_code) {
decoded_chars.push(chr);
} else {
panic!("Invalid character code {} at position {}", char_code, i);
}
}
decoded_chars.into_iter().collect()
}