@@ -4,9 +4,8 @@ use elliptic_curve::bigint::{ArrayEncoding, U256};
44use elliptic_curve:: consts:: { U4 , U16 , U48 } ;
55use elliptic_curve:: ops:: Reduce ;
66use elliptic_curve:: subtle:: { Choice , ConditionallySelectable , ConstantTimeEq } ;
7- use hash2curve:: {
8- GroupDigest , Isogeny , IsogenyCoefficients , MapToCurve , OsswuMap , OsswuMapParams , Sgn0 ,
9- } ;
7+ use hash2curve:: { GroupDigest , MapToCurve } ;
8+ use primeorder:: osswu:: { OsswuMap , OsswuMapParams , Sgn0 } ;
109
1110use crate :: { AffinePoint , ProjectivePoint , Scalar , Secp256k1 } ;
1211
@@ -134,7 +133,7 @@ impl MapToCurve for Secp256k1 {
134133
135134 fn map_to_curve ( element : FieldElement ) -> ProjectivePoint {
136135 let ( rx, ry) = element. osswu ( ) ;
137- let ( qx, qy) = FieldElement :: isogeny ( rx, ry) ;
136+ let ( qx, qy) = isogeny ( rx, ry) ;
138137
139138 AffinePoint {
140139 x : qx,
@@ -163,96 +162,114 @@ impl Reduce<Array<u8, U48>> for Scalar {
163162 }
164163}
165164
166- impl Isogeny for FieldElement {
167- type Degree = U4 ;
168-
169- // See section E.1 in
170- // <https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/>
171- const COEFFICIENTS : IsogenyCoefficients < Self > = IsogenyCoefficients {
172- xnum : & [
173- FieldElement :: from_bytes_unchecked ( & [
174- 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 ,
175- 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8d ,
176- 0xaa , 0xaa , 0xa8 , 0xc7 ,
177- ] ) ,
178- FieldElement :: from_bytes_unchecked ( & [
179- 0x07 , 0xd3 , 0xd4 , 0xc8 , 0x0b , 0xc3 , 0x21 , 0xd5 , 0xb9 , 0xf3 , 0x15 , 0xce , 0xa7 , 0xfd ,
180- 0x44 , 0xc5 , 0xd5 , 0x95 , 0xd2 , 0xfc , 0x0b , 0xf6 , 0x3b , 0x92 , 0xdf , 0xff , 0x10 , 0x44 ,
181- 0xf1 , 0x7c , 0x65 , 0x81 ,
182- ] ) ,
183- FieldElement :: from_bytes_unchecked ( & [
184- 0x53 , 0x4c , 0x32 , 0x8d , 0x23 , 0xf2 , 0x34 , 0xe6 , 0xe2 , 0xa4 , 0x13 , 0xde , 0xca , 0x25 ,
185- 0xca , 0xec , 0xe4 , 0x50 , 0x61 , 0x44 , 0x03 , 0x7c , 0x40 , 0x31 , 0x4e , 0xcb , 0xd0 , 0xb5 ,
186- 0x3d , 0x9d , 0xd2 , 0x62 ,
187- ] ) ,
188- FieldElement :: from_bytes_unchecked ( & [
189- 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 ,
190- 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8d ,
191- 0xaa , 0xaa , 0xa8 , 0x8c ,
192- ] ) ,
193- ] ,
194- xden : & [
195- FieldElement :: from_bytes_unchecked ( & [
196- 0xd3 , 0x57 , 0x71 , 0x19 , 0x3d , 0x94 , 0x91 , 0x8a , 0x9c , 0xa3 , 0x4c , 0xcb , 0xb7 , 0xb6 ,
197- 0x40 , 0xdd , 0x86 , 0xcd , 0x40 , 0x95 , 0x42 , 0xf8 , 0x48 , 0x7d , 0x9f , 0xe6 , 0xb7 , 0x45 ,
198- 0x78 , 0x1e , 0xb4 , 0x9b ,
199- ] ) ,
200- FieldElement :: from_bytes_unchecked ( & [
201- 0xed , 0xad , 0xc6 , 0xf6 , 0x43 , 0x83 , 0xdc , 0x1d , 0xf7 , 0xc4 , 0xb2 , 0xd5 , 0x1b , 0x54 ,
202- 0x22 , 0x54 , 0x06 , 0xd3 , 0x6b , 0x64 , 0x1f , 0x5e , 0x41 , 0xbb , 0xc5 , 0x2a , 0x56 , 0x61 ,
203- 0x2a , 0x8c , 0x6d , 0x14 ,
204- ] ) ,
205- FieldElement :: from_bytes_unchecked ( & [
206- 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
207- 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
208- 0x00 , 0x00 , 0x00 , 0x01 ,
209- ] ) ,
210- ] ,
211- ynum : & [
212- FieldElement :: from_bytes_unchecked ( & [
213- 0x4b , 0xda , 0x12 , 0xf6 , 0x84 , 0xbd , 0xa1 , 0x2f , 0x68 , 0x4b , 0xda , 0x12 , 0xf6 , 0x84 ,
214- 0xbd , 0xa1 , 0x2f , 0x68 , 0x4b , 0xda , 0x12 , 0xf6 , 0x84 , 0xbd , 0xa1 , 0x2f , 0x68 , 0x4b ,
215- 0x8e , 0x38 , 0xe2 , 0x3c ,
216- ] ) ,
217- FieldElement :: from_bytes_unchecked ( & [
218- 0xc7 , 0x5e , 0x0c , 0x32 , 0xd5 , 0xcb , 0x7c , 0x0f , 0xa9 , 0xd0 , 0xa5 , 0x4b , 0x12 , 0xa0 ,
219- 0xa6 , 0xd5 , 0x64 , 0x7a , 0xb0 , 0x46 , 0xd6 , 0x86 , 0xda , 0x6f , 0xdf , 0xfc , 0x90 , 0xfc ,
220- 0x20 , 0x1d , 0x71 , 0xa3 ,
221- ] ) ,
222- FieldElement :: from_bytes_unchecked ( & [
223- 0x29 , 0xa6 , 0x19 , 0x46 , 0x91 , 0xf9 , 0x1a , 0x73 , 0x71 , 0x52 , 0x09 , 0xef , 0x65 , 0x12 ,
224- 0xe5 , 0x76 , 0x72 , 0x28 , 0x30 , 0xa2 , 0x01 , 0xbe , 0x20 , 0x18 , 0xa7 , 0x65 , 0xe8 , 0x5a ,
225- 0x9e , 0xce , 0xe9 , 0x31 ,
226- ] ) ,
227- FieldElement :: from_bytes_unchecked ( & [
228- 0x2f , 0x68 , 0x4b , 0xda , 0x12 , 0xf6 , 0x84 , 0xbd , 0xa1 , 0x2f , 0x68 , 0x4b , 0xda , 0x12 ,
229- 0xf6 , 0x84 , 0xbd , 0xa1 , 0x2f , 0x68 , 0x4b , 0xda , 0x12 , 0xf6 , 0x84 , 0xbd , 0xa1 , 0x2f ,
230- 0x38 , 0xe3 , 0x8d , 0x84 ,
231- ] ) ,
232- ] ,
233- yden : & [
234- FieldElement :: from_bytes_unchecked ( & [
235- 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff ,
236- 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xfe ,
237- 0xff , 0xff , 0xf9 , 0x3b ,
238- ] ) ,
239- FieldElement :: from_bytes_unchecked ( & [
240- 0x7a , 0x06 , 0x53 , 0x4b , 0xb8 , 0xbd , 0xb4 , 0x9f , 0xd5 , 0xe9 , 0xe6 , 0x63 , 0x27 , 0x22 ,
241- 0xc2 , 0x98 , 0x94 , 0x67 , 0xc1 , 0xbf , 0xc8 , 0xe8 , 0xd9 , 0x78 , 0xdf , 0xb4 , 0x25 , 0xd2 ,
242- 0x68 , 0x5c , 0x25 , 0x73 ,
243- ] ) ,
244- FieldElement :: from_bytes_unchecked ( & [
245- 0x64 , 0x84 , 0xaa , 0x71 , 0x65 , 0x45 , 0xca , 0x2c , 0xf3 , 0xa7 , 0x0c , 0x3f , 0xa8 , 0xfe ,
246- 0x33 , 0x7e , 0x0a , 0x3d , 0x21 , 0x16 , 0x2f , 0x0d , 0x62 , 0x99 , 0xa7 , 0xbf , 0x81 , 0x92 ,
247- 0xbf , 0xd2 , 0xa7 , 0x6f ,
248- ] ) ,
249- FieldElement :: from_bytes_unchecked ( & [
250- 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
251- 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
252- 0x00 , 0x00 , 0x00 , 0x01 ,
253- ] ) ,
254- ] ,
255- } ;
165+ // See section E.1 in
166+ // <https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/>
167+ fn isogeny ( x : FieldElement , y : FieldElement ) -> ( FieldElement , FieldElement ) {
168+ const XNUM : [ FieldElement ; 4 ] = [
169+ FieldElement :: from_bytes_unchecked ( & [
170+ 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 ,
171+ 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8d ,
172+ 0xaa , 0xaa , 0xa8 , 0xc7 ,
173+ ] ) ,
174+ FieldElement :: from_bytes_unchecked ( & [
175+ 0x07 , 0xd3 , 0xd4 , 0xc8 , 0x0b , 0xc3 , 0x21 , 0xd5 , 0xb9 , 0xf3 , 0x15 , 0xce , 0xa7 , 0xfd ,
176+ 0x44 , 0xc5 , 0xd5 , 0x95 , 0xd2 , 0xfc , 0x0b , 0xf6 , 0x3b , 0x92 , 0xdf , 0xff , 0x10 , 0x44 ,
177+ 0xf1 , 0x7c , 0x65 , 0x81 ,
178+ ] ) ,
179+ FieldElement :: from_bytes_unchecked ( & [
180+ 0x53 , 0x4c , 0x32 , 0x8d , 0x23 , 0xf2 , 0x34 , 0xe6 , 0xe2 , 0xa4 , 0x13 , 0xde , 0xca , 0x25 ,
181+ 0xca , 0xec , 0xe4 , 0x50 , 0x61 , 0x44 , 0x03 , 0x7c , 0x40 , 0x31 , 0x4e , 0xcb , 0xd0 , 0xb5 ,
182+ 0x3d , 0x9d , 0xd2 , 0x62 ,
183+ ] ) ,
184+ FieldElement :: from_bytes_unchecked ( & [
185+ 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 ,
186+ 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8e , 0x38 , 0xe3 , 0x8d ,
187+ 0xaa , 0xaa , 0xa8 , 0x8c ,
188+ ] ) ,
189+ ] ;
190+ const XDEN : [ FieldElement ; 3 ] = [
191+ FieldElement :: from_bytes_unchecked ( & [
192+ 0xd3 , 0x57 , 0x71 , 0x19 , 0x3d , 0x94 , 0x91 , 0x8a , 0x9c , 0xa3 , 0x4c , 0xcb , 0xb7 , 0xb6 ,
193+ 0x40 , 0xdd , 0x86 , 0xcd , 0x40 , 0x95 , 0x42 , 0xf8 , 0x48 , 0x7d , 0x9f , 0xe6 , 0xb7 , 0x45 ,
194+ 0x78 , 0x1e , 0xb4 , 0x9b ,
195+ ] ) ,
196+ FieldElement :: from_bytes_unchecked ( & [
197+ 0xed , 0xad , 0xc6 , 0xf6 , 0x43 , 0x83 , 0xdc , 0x1d , 0xf7 , 0xc4 , 0xb2 , 0xd5 , 0x1b , 0x54 ,
198+ 0x22 , 0x54 , 0x06 , 0xd3 , 0x6b , 0x64 , 0x1f , 0x5e , 0x41 , 0xbb , 0xc5 , 0x2a , 0x56 , 0x61 ,
199+ 0x2a , 0x8c , 0x6d , 0x14 ,
200+ ] ) ,
201+ FieldElement :: from_bytes_unchecked ( & [
202+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
203+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
204+ 0x00 , 0x00 , 0x00 , 0x01 ,
205+ ] ) ,
206+ ] ;
207+ const YNUM : [ FieldElement ; 4 ] = [
208+ FieldElement :: from_bytes_unchecked ( & [
209+ 0x4b , 0xda , 0x12 , 0xf6 , 0x84 , 0xbd , 0xa1 , 0x2f , 0x68 , 0x4b , 0xda , 0x12 , 0xf6 , 0x84 ,
210+ 0xbd , 0xa1 , 0x2f , 0x68 , 0x4b , 0xda , 0x12 , 0xf6 , 0x84 , 0xbd , 0xa1 , 0x2f , 0x68 , 0x4b ,
211+ 0x8e , 0x38 , 0xe2 , 0x3c ,
212+ ] ) ,
213+ FieldElement :: from_bytes_unchecked ( & [
214+ 0xc7 , 0x5e , 0x0c , 0x32 , 0xd5 , 0xcb , 0x7c , 0x0f , 0xa9 , 0xd0 , 0xa5 , 0x4b , 0x12 , 0xa0 ,
215+ 0xa6 , 0xd5 , 0x64 , 0x7a , 0xb0 , 0x46 , 0xd6 , 0x86 , 0xda , 0x6f , 0xdf , 0xfc , 0x90 , 0xfc ,
216+ 0x20 , 0x1d , 0x71 , 0xa3 ,
217+ ] ) ,
218+ FieldElement :: from_bytes_unchecked ( & [
219+ 0x29 , 0xa6 , 0x19 , 0x46 , 0x91 , 0xf9 , 0x1a , 0x73 , 0x71 , 0x52 , 0x09 , 0xef , 0x65 , 0x12 ,
220+ 0xe5 , 0x76 , 0x72 , 0x28 , 0x30 , 0xa2 , 0x01 , 0xbe , 0x20 , 0x18 , 0xa7 , 0x65 , 0xe8 , 0x5a ,
221+ 0x9e , 0xce , 0xe9 , 0x31 ,
222+ ] ) ,
223+ FieldElement :: from_bytes_unchecked ( & [
224+ 0x2f , 0x68 , 0x4b , 0xda , 0x12 , 0xf6 , 0x84 , 0xbd , 0xa1 , 0x2f , 0x68 , 0x4b , 0xda , 0x12 ,
225+ 0xf6 , 0x84 , 0xbd , 0xa1 , 0x2f , 0x68 , 0x4b , 0xda , 0x12 , 0xf6 , 0x84 , 0xbd , 0xa1 , 0x2f ,
226+ 0x38 , 0xe3 , 0x8d , 0x84 ,
227+ ] ) ,
228+ ] ;
229+ const YDEN : [ FieldElement ; 4 ] = [
230+ FieldElement :: from_bytes_unchecked ( & [
231+ 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff ,
232+ 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0xfe ,
233+ 0xff , 0xff , 0xf9 , 0x3b ,
234+ ] ) ,
235+ FieldElement :: from_bytes_unchecked ( & [
236+ 0x7a , 0x06 , 0x53 , 0x4b , 0xb8 , 0xbd , 0xb4 , 0x9f , 0xd5 , 0xe9 , 0xe6 , 0x63 , 0x27 , 0x22 ,
237+ 0xc2 , 0x98 , 0x94 , 0x67 , 0xc1 , 0xbf , 0xc8 , 0xe8 , 0xd9 , 0x78 , 0xdf , 0xb4 , 0x25 , 0xd2 ,
238+ 0x68 , 0x5c , 0x25 , 0x73 ,
239+ ] ) ,
240+ FieldElement :: from_bytes_unchecked ( & [
241+ 0x64 , 0x84 , 0xaa , 0x71 , 0x65 , 0x45 , 0xca , 0x2c , 0xf3 , 0xa7 , 0x0c , 0x3f , 0xa8 , 0xfe ,
242+ 0x33 , 0x7e , 0x0a , 0x3d , 0x21 , 0x16 , 0x2f , 0x0d , 0x62 , 0x99 , 0xa7 , 0xbf , 0x81 , 0x92 ,
243+ 0xbf , 0xd2 , 0xa7 , 0x6f ,
244+ ] ) ,
245+ FieldElement :: from_bytes_unchecked ( & [
246+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
247+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
248+ 0x00 , 0x00 , 0x00 , 0x01 ,
249+ ] ) ,
250+ ] ;
251+
252+ let mut xs = Array :: < FieldElement , U4 > :: default ( ) ;
253+ xs[ 0 ] = FieldElement :: ONE ;
254+ xs[ 1 ] = x;
255+ xs[ 2 ] = x. square ( ) ;
256+ for i in 3 ..4 {
257+ xs[ i] = xs[ i - 1 ] * x;
258+ }
259+ let x_num = compute_iso ( & xs, & XNUM ) ;
260+ let x_den = compute_iso ( & xs, & XDEN ) . invert ( ) . unwrap ( ) ;
261+ let y_num = compute_iso ( & xs, & YNUM ) * y;
262+ let y_den = compute_iso ( & xs, & YDEN ) . invert ( ) . unwrap ( ) ;
263+
264+ ( x_num * x_den, y_num * y_den)
265+ }
266+
267+ fn compute_iso ( xxs : & [ FieldElement ] , k : & [ FieldElement ] ) -> FieldElement {
268+ let mut xx = FieldElement :: ZERO ;
269+ for ( xi, ki) in xxs. iter ( ) . zip ( k. iter ( ) ) {
270+ xx += * xi * ki;
271+ }
272+ xx
256273}
257274
258275#[ cfg( test) ]
0 commit comments