| 1 | module edwards25519 |
| 2 | |
| 3 | import os |
| 4 | import rand |
| 5 | import encoding.hex |
| 6 | |
| 7 | const github_job = os.getenv('GITHUB_JOB') |
| 8 | |
| 9 | fn testsuite_begin() { |
| 10 | if github_job != '' { |
| 11 | // ensure that the CI does not run flaky tests: |
| 12 | rand.seed([u32(0xffff24), 0xabcd]) |
| 13 | } |
| 14 | } |
| 15 | |
| 16 | // test_bytes_montgomery tests the set_bytes_with_clamping+bytes_montgomery path |
| 17 | // equivalence to curve25519.X25519 for basepoint scalar multiplications. |
| 18 | // |
| 19 | // Note that you can't actually implement X25519 with this package because |
| 20 | // there is no SetBytesMontgomery, and it would not be possible to implement |
| 21 | // it properly: points on the twist would get rejected, and the Scalar returned |
| 22 | // by set_bytes_with_clamping does not preserve its cofactor-clearing properties. |
| 23 | // |
| 24 | // Disabled curve25519 not available yet, but maybe can use own curve25519 |
| 25 | /* |
| 26 | fn fn_mon(scalar [32]u8) bool { |
| 27 | mut s := new_scalar().set_bytes_with_clamping(scalar[..]) |
| 28 | p := (&Point{}).scalar_base_mult(s) |
| 29 | got := p.bytes_montgomery() |
| 30 | want, _ := curve25519.X25519(scalar[..], curve25519.Basepoint) |
| 31 | return bytes.equal(got, want) |
| 32 | } |
| 33 | |
| 34 | fn test_bytes_montgomery() { |
| 35 | /* f := fn(scalar [32]u8) bool { |
| 36 | s := new_scalar().set_bytes_with_clamping(scalar[..]) |
| 37 | p := (&Point{}).scalar_base_mult(s) |
| 38 | got := p.bytes_montgomery() |
| 39 | want, _ := curve25519.X25519(scalar[..], curve25519.Basepoint) |
| 40 | return bytes.equal(got, want) |
| 41 | } */ |
| 42 | if err := quick.Check(f, nil); err != nil { |
| 43 | t.Error(err) |
| 44 | } |
| 45 | }*/ |
| 46 | |
| 47 | fn test_bytes_montgomery_sodium() { |
| 48 | // Generated with libsodium.js 1.0.18 |
| 49 | // crypto_sign_keypair().pubkey |
| 50 | pubkey := '3bf918ffc2c955dc895bf145f566fb96623c1cadbe040091175764b5fde322c0' |
| 51 | mut p := Point{} |
| 52 | p.set_bytes(hex.decode(pubkey)!)! |
| 53 | |
| 54 | // crypto_sign_ed25519_pk_to_curve25519(pubkey) |
| 55 | want := 'efc6c9d0738e9ea18d738ad4a2653631558931b0f1fde4dd58c436d19686dc28' |
| 56 | got := hex.encode(p.bytes_montgomery()) |
| 57 | assert got == want |
| 58 | } |
| 59 | |
| 60 | fn test_bytes_montgomery_infinity() { |
| 61 | mut p := new_identity_point() |
| 62 | want := '0000000000000000000000000000000000000000000000000000000000000000' |
| 63 | got := hex.encode(p.bytes_montgomery()) |
| 64 | |
| 65 | assert got == want |
| 66 | } |
| 67 | |
| 68 | const loworder_string = '26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85' |
| 69 | const loworder_bytes = hex.decode(loworder_string) or { []u8{} } |
| 70 | |
| 71 | fn fn_cofactor(mut data []u8) bool { |
| 72 | if data.len != 64 { |
| 73 | panic('data.len should be 64') |
| 74 | } |
| 75 | mut loworder := Point{} |
| 76 | loworder.set_bytes(loworder_bytes) or { return false } |
| 77 | |
| 78 | mut s := new_scalar() |
| 79 | mut p := Point{} |
| 80 | mut p8 := Point{} |
| 81 | s.set_uniform_bytes(data) or { panic(err) } |
| 82 | p.scalar_base_mult(mut s) |
| 83 | p8.mult_by_cofactor(p) |
| 84 | |
| 85 | assert check_on_curve(p8) == true |
| 86 | |
| 87 | // 8 * p == (8 * s) * B |
| 88 | mut sc := Scalar{ |
| 89 | s: [32]u8{} |
| 90 | } |
| 91 | sc.s[0] = u8(0x08) |
| 92 | s.multiply(s, sc) |
| 93 | mut pp := Point{} |
| 94 | pp.scalar_base_mult(mut s) |
| 95 | if p8.equal(pp) != 1 { |
| 96 | return false |
| 97 | } |
| 98 | |
| 99 | // 8 * p == 8 * (loworder + p) |
| 100 | pp.add(p, loworder) |
| 101 | pp.mult_by_cofactor(pp) |
| 102 | if p8.equal(pp) != 1 { |
| 103 | return false |
| 104 | } |
| 105 | |
| 106 | // 8 * p == p + p + p + p + p + p + p + p |
| 107 | pp.set(new_identity_point()) |
| 108 | for i := 0; i < 8; i++ { |
| 109 | pp.add(pp, p) |
| 110 | } |
| 111 | return p8.equal(pp) == 1 |
| 112 | } |
| 113 | |
| 114 | fn test_mult_by_cofactor() { |
| 115 | mut loworder := Point{} |
| 116 | mut data := rand.bytes(64)! |
| 117 | |
| 118 | assert fn_cofactor(mut data) == true |
| 119 | } |
| 120 | |
| 121 | fn invert_works(mut xinv Scalar, x NotZeroScalar) bool { |
| 122 | xinv.invert(x) |
| 123 | mut check := Scalar{} |
| 124 | check.multiply(x, xinv) |
| 125 | return check == sc_one && is_reduced(xinv) |
| 126 | } |
| 127 | |
| 128 | fn test_scalar_invert() { |
| 129 | nsc := generate_notzero_scalar(5) or { panic(err) } |
| 130 | mut xsc := generate_scalar(5) or { panic(err) } |
| 131 | assert invert_works(mut xsc, nsc) == true |
| 132 | |
| 133 | mut zero := new_scalar() |
| 134 | mut xx := new_scalar() |
| 135 | xx.invert(zero) |
| 136 | assert xx.equal(zero) == 1 |
| 137 | } |
| 138 | |
| 139 | fn test_multiscalarmultmatchesbasemult() { |
| 140 | for i in 0 .. 6 { |
| 141 | x := generate_scalar(100) or { panic(err) } |
| 142 | y := generate_scalar(5) or { panic(err) } |
| 143 | z := generate_scalar(2) or { panic(err) } |
| 144 | assert multiscalarmultmatchesbasemult(x, y, z) == true |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | fn multiscalarmultmatchesbasemult(xx Scalar, yy Scalar, zz Scalar) bool { |
| 149 | mut x := xx |
| 150 | mut y := yy |
| 151 | mut z := zz |
| 152 | |
| 153 | mut p := Point{} |
| 154 | mut q1 := Point{} |
| 155 | mut q2 := Point{} |
| 156 | mut q3 := Point{} |
| 157 | mut check := Point{} |
| 158 | mut b := new_generator_point() |
| 159 | |
| 160 | p.multi_scalar_mult([x, y, z], [b, b, b]) |
| 161 | |
| 162 | q1.scalar_base_mult(mut x) |
| 163 | q2.scalar_base_mult(mut y) |
| 164 | q3.scalar_base_mult(mut z) |
| 165 | check.add(q1, q2) |
| 166 | check.add(check, q3) |
| 167 | |
| 168 | check_on_curve(p, check, q1, q2, q3) |
| 169 | return p.equal(check) == 1 |
| 170 | } |
| 171 | |
| 172 | fn vartime_multiscala_rmultmatches_basemult(xx Scalar, yy Scalar, zz Scalar) bool { |
| 173 | mut x := xx |
| 174 | mut y := yy |
| 175 | mut z := zz |
| 176 | mut p := Point{} |
| 177 | mut q1 := Point{} |
| 178 | mut q2 := Point{} |
| 179 | mut q3 := Point{} |
| 180 | mut check := Point{} |
| 181 | mut b := new_generator_point() |
| 182 | |
| 183 | p.vartime_multiscalar_mult([x, y, z], [b, b, b]) |
| 184 | |
| 185 | q1.scalar_base_mult(mut x) |
| 186 | q2.scalar_base_mult(mut y) |
| 187 | q3.scalar_base_mult(mut z) |
| 188 | check.add(q1, q2) |
| 189 | check.add(check, q3) |
| 190 | |
| 191 | check_on_curve(p, check, q1, q2, q3) |
| 192 | return p.equal(check) == 1 |
| 193 | } |
| 194 | |
| 195 | fn test_vartimemultiscalarmultmatchesbasemult() { |
| 196 | for i in 0 .. 5 { |
| 197 | x := generate_scalar(100) or { panic(err) } |
| 198 | y := generate_scalar(5) or { panic(err) } |
| 199 | z := generate_scalar(2) or { panic(err) } |
| 200 | assert vartime_multiscala_rmultmatches_basemult(x, y, z) == true |
| 201 | } |
| 202 | } |
| 203 | |