@pulse-compute/crypto 1.0.0-beta.5 → 1.0.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +56 -4
  2. package/dist/contracts.d.ts +34 -12
  3. package/dist/contracts.d.ts.map +1 -1
  4. package/dist/contracts.js +9 -3
  5. package/dist/contracts.js.map +1 -1
  6. package/dist/index.d.ts +3 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +17 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/internal/rsa.d.ts +58 -0
  11. package/dist/internal/rsa.d.ts.map +1 -0
  12. package/dist/internal/rsa.js +185 -0
  13. package/dist/internal/rsa.js.map +1 -0
  14. package/dist/internal/verification.d.ts +3 -3
  15. package/dist/internal/verification.d.ts.map +1 -1
  16. package/dist/internal/verification.js +2 -2
  17. package/dist/internal/verification.js.map +1 -1
  18. package/guests/es256-rustcrypto/README.md +43 -0
  19. package/guests/es256-rustcrypto/build.cjs +297 -0
  20. package/guests/es256-rustcrypto/prebuilt/es256-verifier.unoptimized.wasm +0 -0
  21. package/guests/es256-rustcrypto/prebuilt/es256-verifier.wasm +0 -0
  22. package/guests/es256-rustcrypto/probe/.cargo/config.toml +18 -0
  23. package/guests/es256-rustcrypto/probe/Cargo.lock +238 -0
  24. package/guests/es256-rustcrypto/probe/Cargo.toml +26 -0
  25. package/guests/es256-rustcrypto/probe/README.md +35 -0
  26. package/guests/es256-rustcrypto/probe/rust-toolchain.toml +5 -0
  27. package/guests/es256-rustcrypto/probe/src/lib.rs +108 -0
  28. package/guests/es256-rustcrypto/pulse.guest-unit.json +119 -0
  29. package/guests/es256-rustcrypto/source/.cargo/config.toml +18 -0
  30. package/guests/es256-rustcrypto/source/Cargo.lock +265 -0
  31. package/guests/es256-rustcrypto/source/Cargo.toml +23 -0
  32. package/guests/es256-rustcrypto/source/README.md +26 -0
  33. package/guests/es256-rustcrypto/source/bearssl/LICENSE.txt +21 -0
  34. package/guests/es256-rustcrypto/source/bearssl/UPSTREAM.json +49 -0
  35. package/guests/es256-rustcrypto/source/bearssl/inc/bearssl.h +170 -0
  36. package/guests/es256-rustcrypto/source/bearssl/inc/bearssl_aead.h +1059 -0
  37. package/guests/es256-rustcrypto/source/bearssl/inc/bearssl_block.h +2618 -0
  38. package/guests/es256-rustcrypto/source/bearssl/inc/bearssl_ec.h +883 -0
  39. package/guests/es256-rustcrypto/source/bearssl/inc/bearssl_hash.h +1346 -0
  40. package/guests/es256-rustcrypto/source/bearssl/inc/bearssl_hmac.h +241 -0
  41. package/guests/es256-rustcrypto/source/bearssl/inc/bearssl_kdf.h +185 -0
  42. package/guests/es256-rustcrypto/source/bearssl/inc/bearssl_pem.h +294 -0
  43. package/guests/es256-rustcrypto/source/bearssl/inc/bearssl_prf.h +150 -0
  44. package/guests/es256-rustcrypto/source/bearssl/inc/bearssl_rand.h +397 -0
  45. package/guests/es256-rustcrypto/source/bearssl/inc/bearssl_rsa.h +1366 -0
  46. package/guests/es256-rustcrypto/source/bearssl/inc/bearssl_ssl.h +4296 -0
  47. package/guests/es256-rustcrypto/source/bearssl/inc/bearssl_x509.h +1397 -0
  48. package/guests/es256-rustcrypto/source/bearssl/src/codec/ccopy.c +44 -0
  49. package/guests/es256-rustcrypto/source/bearssl/src/codec/dec32be.c +38 -0
  50. package/guests/es256-rustcrypto/source/bearssl/src/codec/enc32be.c +38 -0
  51. package/guests/es256-rustcrypto/source/bearssl/src/config.h +229 -0
  52. package/guests/es256-rustcrypto/source/bearssl/src/inner.h +2532 -0
  53. package/guests/es256-rustcrypto/source/bearssl/src/int/i31_add.c +46 -0
  54. package/guests/es256-rustcrypto/source/bearssl/src/int/i31_bitlen.c +44 -0
  55. package/guests/es256-rustcrypto/source/bearssl/src/int/i31_decmod.c +124 -0
  56. package/guests/es256-rustcrypto/source/bearssl/src/int/i31_decode.c +57 -0
  57. package/guests/es256-rustcrypto/source/bearssl/src/int/i31_decred.c +103 -0
  58. package/guests/es256-rustcrypto/source/bearssl/src/int/i31_encode.c +79 -0
  59. package/guests/es256-rustcrypto/source/bearssl/src/int/i31_fmont.c +60 -0
  60. package/guests/es256-rustcrypto/source/bearssl/src/int/i31_iszero.c +39 -0
  61. package/guests/es256-rustcrypto/source/bearssl/src/int/i31_moddiv.c +488 -0
  62. package/guests/es256-rustcrypto/source/bearssl/src/int/i31_modpow.c +65 -0
  63. package/guests/es256-rustcrypto/source/bearssl/src/int/i31_modpow2.c +160 -0
  64. package/guests/es256-rustcrypto/source/bearssl/src/int/i31_montmul.c +93 -0
  65. package/guests/es256-rustcrypto/source/bearssl/src/int/i31_mulacc.c +61 -0
  66. package/guests/es256-rustcrypto/source/bearssl/src/int/i31_muladd.c +157 -0
  67. package/guests/es256-rustcrypto/source/bearssl/src/int/i31_ninv31.c +39 -0
  68. package/guests/es256-rustcrypto/source/bearssl/src/int/i31_reduce.c +66 -0
  69. package/guests/es256-rustcrypto/source/bearssl/src/int/i31_rshift.c +47 -0
  70. package/guests/es256-rustcrypto/source/bearssl/src/int/i31_sub.c +46 -0
  71. package/guests/es256-rustcrypto/source/bearssl/src/int/i31_tmont.c +36 -0
  72. package/guests/es256-rustcrypto/source/bearssl/src/int/i32_div32.c +56 -0
  73. package/guests/es256-rustcrypto/source/bearssl/src/rsa/rsa_i31_priv.c +203 -0
  74. package/guests/es256-rustcrypto/source/bearssl/src/rsa/rsa_i31_pub.c +106 -0
  75. package/guests/es256-rustcrypto/source/bearssl/src/rsa/rsa_pkcs1_sig_pad.c +100 -0
  76. package/guests/es256-rustcrypto/source/build.rs +38 -0
  77. package/guests/es256-rustcrypto/source/freestanding/string.h +8 -0
  78. package/guests/es256-rustcrypto/source/rs256.c +103 -0
  79. package/guests/es256-rustcrypto/source/rust-toolchain.toml +5 -0
  80. package/guests/es256-rustcrypto/source/src/lib.rs +308 -0
  81. package/package.json +6 -4
  82. package/pulsewasm.native.cjs +66 -0
  83. package/src/provider.cjs +71 -1
  84. package/src/provider.d.cts +6 -0
@@ -0,0 +1,203 @@
1
+ /*
2
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining
5
+ * a copy of this software and associated documentation files (the
6
+ * "Software"), to deal in the Software without restriction, including
7
+ * without limitation the rights to use, copy, modify, merge, publish,
8
+ * distribute, sublicense, and/or sell copies of the Software, and to
9
+ * permit persons to whom the Software is furnished to do so, subject to
10
+ * the following conditions:
11
+ *
12
+ * The above copyright notice and this permission notice shall be
13
+ * included in all copies or substantial portions of the Software.
14
+ *
15
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+
25
+ #include "inner.h"
26
+
27
+ #define U (2 + ((BR_MAX_RSA_FACTOR + 30) / 31))
28
+ #define TLEN (8 * U)
29
+
30
+ /* see bearssl_rsa.h */
31
+ uint32_t
32
+ br_rsa_i31_private(unsigned char *x, const br_rsa_private_key *sk)
33
+ {
34
+ const unsigned char *p, *q;
35
+ size_t plen, qlen;
36
+ size_t fwlen;
37
+ uint32_t p0i, q0i;
38
+ size_t xlen, u;
39
+ uint32_t tmp[1 + TLEN];
40
+ long z;
41
+ uint32_t *mp, *mq, *s1, *s2, *t1, *t2, *t3;
42
+ uint32_t r;
43
+
44
+ /*
45
+ * Compute the actual lengths of p and q, in bytes.
46
+ * These lengths are not considered secret (we cannot really hide
47
+ * them anyway in constant-time code).
48
+ */
49
+ p = sk->p;
50
+ plen = sk->plen;
51
+ while (plen > 0 && *p == 0) {
52
+ p ++;
53
+ plen --;
54
+ }
55
+ q = sk->q;
56
+ qlen = sk->qlen;
57
+ while (qlen > 0 && *q == 0) {
58
+ q ++;
59
+ qlen --;
60
+ }
61
+
62
+ /*
63
+ * Compute the maximum factor length, in words.
64
+ */
65
+ z = (long)(plen > qlen ? plen : qlen) << 3;
66
+ fwlen = 1;
67
+ while (z > 0) {
68
+ z -= 31;
69
+ fwlen ++;
70
+ }
71
+
72
+ /*
73
+ * Round up the word length to an even number.
74
+ */
75
+ fwlen += (fwlen & 1);
76
+
77
+ /*
78
+ * We need to fit at least 6 values in the stack buffer.
79
+ */
80
+ if (6 * fwlen > TLEN) {
81
+ return 0;
82
+ }
83
+
84
+ /*
85
+ * Compute modulus length (in bytes).
86
+ */
87
+ xlen = (sk->n_bitlen + 7) >> 3;
88
+
89
+ /*
90
+ * Decode q.
91
+ */
92
+ mq = tmp;
93
+ br_i31_decode(mq, q, qlen);
94
+
95
+ /*
96
+ * Decode p.
97
+ */
98
+ t1 = mq + fwlen;
99
+ br_i31_decode(t1, p, plen);
100
+
101
+ /*
102
+ * Compute the modulus (product of the two factors), to compare
103
+ * it with the source value. We use br_i31_mulacc(), since it's
104
+ * already used later on.
105
+ */
106
+ t2 = mq + 2 * fwlen;
107
+ br_i31_zero(t2, mq[0]);
108
+ br_i31_mulacc(t2, mq, t1);
109
+
110
+ /*
111
+ * We encode the modulus into bytes, to perform the comparison
112
+ * with bytes. We know that the product length, in bytes, is
113
+ * exactly xlen.
114
+ * The comparison actually computes the carry when subtracting
115
+ * the modulus from the source value; that carry must be 1 for
116
+ * a value in the correct range. We keep it in r, which is our
117
+ * accumulator for the error code.
118
+ */
119
+ t3 = mq + 4 * fwlen;
120
+ br_i31_encode(t3, xlen, t2);
121
+ u = xlen;
122
+ r = 0;
123
+ while (u > 0) {
124
+ uint32_t wn, wx;
125
+
126
+ u --;
127
+ wn = ((unsigned char *)t3)[u];
128
+ wx = x[u];
129
+ r = ((wx - (wn + r)) >> 8) & 1;
130
+ }
131
+
132
+ /*
133
+ * Move the decoded p to another temporary buffer.
134
+ */
135
+ mp = mq + 2 * fwlen;
136
+ memmove(mp, t1, fwlen * sizeof *t1);
137
+
138
+ /*
139
+ * Compute s2 = x^dq mod q.
140
+ */
141
+ q0i = br_i31_ninv31(mq[1]);
142
+ s2 = mq + fwlen;
143
+ br_i31_decode_reduce(s2, x, xlen, mq);
144
+ r &= br_i31_modpow_opt(s2, sk->dq, sk->dqlen, mq, q0i,
145
+ mq + 3 * fwlen, TLEN - 3 * fwlen);
146
+
147
+ /*
148
+ * Compute s1 = x^dp mod p.
149
+ */
150
+ p0i = br_i31_ninv31(mp[1]);
151
+ s1 = mq + 3 * fwlen;
152
+ br_i31_decode_reduce(s1, x, xlen, mp);
153
+ r &= br_i31_modpow_opt(s1, sk->dp, sk->dplen, mp, p0i,
154
+ mq + 4 * fwlen, TLEN - 4 * fwlen);
155
+
156
+ /*
157
+ * Compute:
158
+ * h = (s1 - s2)*(1/q) mod p
159
+ * s1 is an integer modulo p, but s2 is modulo q. PKCS#1 is
160
+ * unclear about whether p may be lower than q (some existing,
161
+ * widely deployed implementations of RSA don't tolerate p < q),
162
+ * but we want to support that occurrence, so we need to use the
163
+ * reduction function.
164
+ *
165
+ * Since we use br_i31_decode_reduce() for iq (purportedly, the
166
+ * inverse of q modulo p), we also tolerate improperly large
167
+ * values for this parameter.
168
+ */
169
+ t1 = mq + 4 * fwlen;
170
+ t2 = mq + 5 * fwlen;
171
+ br_i31_reduce(t2, s2, mp);
172
+ br_i31_add(s1, mp, br_i31_sub(s1, t2, 1));
173
+ br_i31_to_monty(s1, mp);
174
+ br_i31_decode_reduce(t1, sk->iq, sk->iqlen, mp);
175
+ br_i31_montymul(t2, s1, t1, mp, p0i);
176
+
177
+ /*
178
+ * h is now in t2. We compute the final result:
179
+ * s = s2 + q*h
180
+ * All these operations are non-modular.
181
+ *
182
+ * We need mq, s2 and t2. We use the t3 buffer as destination.
183
+ * The buffers mp, s1 and t1 are no longer needed, so we can
184
+ * reuse them for t3. Moreover, the first step of the computation
185
+ * is to copy s2 into t3, after which s2 is not needed. Right
186
+ * now, mq is in slot 0, s2 is in slot 1, and t2 is in slot 5.
187
+ * Therefore, we have ample room for t3 by simply using s2.
188
+ */
189
+ t3 = s2;
190
+ br_i31_mulacc(t3, mq, t2);
191
+
192
+ /*
193
+ * Encode the result. Since we already checked the value of xlen,
194
+ * we can just use it right away.
195
+ */
196
+ br_i31_encode(x, xlen, t3);
197
+
198
+ /*
199
+ * The only error conditions remaining at that point are invalid
200
+ * values for p and q (even integers).
201
+ */
202
+ return p0i & q0i & r;
203
+ }
@@ -0,0 +1,106 @@
1
+ /*
2
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining
5
+ * a copy of this software and associated documentation files (the
6
+ * "Software"), to deal in the Software without restriction, including
7
+ * without limitation the rights to use, copy, modify, merge, publish,
8
+ * distribute, sublicense, and/or sell copies of the Software, and to
9
+ * permit persons to whom the Software is furnished to do so, subject to
10
+ * the following conditions:
11
+ *
12
+ * The above copyright notice and this permission notice shall be
13
+ * included in all copies or substantial portions of the Software.
14
+ *
15
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+
25
+ #include "inner.h"
26
+
27
+ /*
28
+ * As a strict minimum, we need four buffers that can hold a
29
+ * modular integer.
30
+ */
31
+ #define TLEN (4 * (2 + ((BR_MAX_RSA_SIZE + 30) / 31)))
32
+
33
+ /* see bearssl_rsa.h */
34
+ uint32_t
35
+ br_rsa_i31_public(unsigned char *x, size_t xlen,
36
+ const br_rsa_public_key *pk)
37
+ {
38
+ const unsigned char *n;
39
+ size_t nlen;
40
+ uint32_t tmp[1 + TLEN];
41
+ uint32_t *m, *a, *t;
42
+ size_t fwlen;
43
+ long z;
44
+ uint32_t m0i, r;
45
+
46
+ /*
47
+ * Get the actual length of the modulus, and see if it fits within
48
+ * our stack buffer. We also check that the length of x[] is valid.
49
+ */
50
+ n = pk->n;
51
+ nlen = pk->nlen;
52
+ while (nlen > 0 && *n == 0) {
53
+ n ++;
54
+ nlen --;
55
+ }
56
+ if (nlen == 0 || nlen > (BR_MAX_RSA_SIZE >> 3) || xlen != nlen) {
57
+ return 0;
58
+ }
59
+ z = (long)nlen << 3;
60
+ fwlen = 1;
61
+ while (z > 0) {
62
+ z -= 31;
63
+ fwlen ++;
64
+ }
65
+ /*
66
+ * Round up length to an even number.
67
+ */
68
+ fwlen += (fwlen & 1);
69
+
70
+ /*
71
+ * The modulus gets decoded into m[].
72
+ * The value to exponentiate goes into a[].
73
+ * The temporaries for modular exponentiation are in t[].
74
+ */
75
+ m = tmp;
76
+ a = m + fwlen;
77
+ t = m + 2 * fwlen;
78
+
79
+ /*
80
+ * Decode the modulus.
81
+ */
82
+ br_i31_decode(m, n, nlen);
83
+ m0i = br_i31_ninv31(m[1]);
84
+
85
+ /*
86
+ * Note: if m[] is even, then m0i == 0. Otherwise, m0i must be
87
+ * an odd integer.
88
+ */
89
+ r = m0i & 1;
90
+
91
+ /*
92
+ * Decode x[] into a[]; we also check that its value is proper.
93
+ */
94
+ r &= br_i31_decode_mod(a, x, xlen, m);
95
+
96
+ /*
97
+ * Compute the modular exponentiation.
98
+ */
99
+ br_i31_modpow_opt(a, pk->e, pk->elen, m, m0i, t, TLEN - 2 * fwlen);
100
+
101
+ /*
102
+ * Encode the result.
103
+ */
104
+ br_i31_encode(x, xlen, a);
105
+ return r;
106
+ }
@@ -0,0 +1,100 @@
1
+ /*
2
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining
5
+ * a copy of this software and associated documentation files (the
6
+ * "Software"), to deal in the Software without restriction, including
7
+ * without limitation the rights to use, copy, modify, merge, publish,
8
+ * distribute, sublicense, and/or sell copies of the Software, and to
9
+ * permit persons to whom the Software is furnished to do so, subject to
10
+ * the following conditions:
11
+ *
12
+ * The above copyright notice and this permission notice shall be
13
+ * included in all copies or substantial portions of the Software.
14
+ *
15
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+
25
+ #include "inner.h"
26
+
27
+ /* see inner.h */
28
+ uint32_t
29
+ br_rsa_pkcs1_sig_pad(const unsigned char *hash_oid,
30
+ const unsigned char *hash, size_t hash_len,
31
+ uint32_t n_bitlen, unsigned char *x)
32
+ {
33
+ size_t u, x3, xlen;
34
+
35
+ /*
36
+ * Padded hash value has format:
37
+ * 00 01 FF .. FF 00 30 x1 30 x2 06 x3 OID 05 00 04 x4 HASH
38
+ *
39
+ * with the following rules:
40
+ *
41
+ * -- Total length is equal to the modulus length (unsigned
42
+ * encoding).
43
+ *
44
+ * -- There must be at least eight bytes of value 0xFF.
45
+ *
46
+ * -- x4 is equal to the hash length (hash_len).
47
+ *
48
+ * -- x3 is equal to the encoded OID value length (hash_oid[0]).
49
+ *
50
+ * -- x2 = x3 + 4.
51
+ *
52
+ * -- x1 = x2 + x4 + 4 = x3 + x4 + 8.
53
+ *
54
+ * Note: the "05 00" is optional (signatures with and without
55
+ * that sequence exist in practice), but notes in PKCS#1 seem to
56
+ * indicate that the presence of that sequence (specifically,
57
+ * an ASN.1 NULL value for the hash parameters) may be slightly
58
+ * more "standard" than the opposite.
59
+ */
60
+ xlen = (n_bitlen + 7) >> 3;
61
+
62
+ if (hash_oid == NULL) {
63
+ if (xlen < hash_len + 11) {
64
+ return 0;
65
+ }
66
+ x[0] = 0x00;
67
+ x[1] = 0x01;
68
+ u = xlen - hash_len;
69
+ memset(x + 2, 0xFF, u - 3);
70
+ x[u - 1] = 0x00;
71
+ } else {
72
+ x3 = hash_oid[0];
73
+
74
+ /*
75
+ * Check that there is enough room for all the elements,
76
+ * including at least eight bytes of value 0xFF.
77
+ */
78
+ if (xlen < (x3 + hash_len + 21)) {
79
+ return 0;
80
+ }
81
+ x[0] = 0x00;
82
+ x[1] = 0x01;
83
+ u = xlen - x3 - hash_len - 11;
84
+ memset(x + 2, 0xFF, u - 2);
85
+ x[u] = 0x00;
86
+ x[u + 1] = 0x30;
87
+ x[u + 2] = x3 + hash_len + 8;
88
+ x[u + 3] = 0x30;
89
+ x[u + 4] = x3 + 4;
90
+ x[u + 5] = 0x06;
91
+ memcpy(x + u + 6, hash_oid, x3 + 1);
92
+ u += x3 + 7;
93
+ x[u ++] = 0x05;
94
+ x[u ++] = 0x00;
95
+ x[u ++] = 0x04;
96
+ x[u ++] = hash_len;
97
+ }
98
+ memcpy(x + u, hash, hash_len);
99
+ return 1;
100
+ }
@@ -0,0 +1,38 @@
1
+ use std::{env, fs, path::PathBuf, process::Command};
2
+
3
+ fn run(command: &mut Command) {
4
+ assert!(command.status().expect("C toolchain invocation failed").success(), "C toolchain failed");
5
+ }
6
+
7
+ fn main() {
8
+ let zig = env::var("PULSE_RSA_ZIG").expect("PULSE_RSA_ZIG must select pinned Zig 0.13.0");
9
+ let version = Command::new(&zig).arg("version").output().expect("Zig unavailable");
10
+ assert!(version.status.success());
11
+ assert_eq!(String::from_utf8(version.stdout).unwrap().trim(), "0.13.0");
12
+ let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
13
+ let mut sources = vec![PathBuf::from("rs256.c")];
14
+ for dir in ["bearssl/src/int", "bearssl/src/rsa", "bearssl/src/codec"] {
15
+ for entry in fs::read_dir(dir).unwrap() {
16
+ let path = entry.unwrap().path();
17
+ if path.extension().is_some_and(|ext| ext == "c") { sources.push(path); }
18
+ }
19
+ }
20
+ sources.sort();
21
+ let mut objects = Vec::new();
22
+ for (index, source) in sources.iter().enumerate() {
23
+ let object = out.join(format!("rsa-{index}.o"));
24
+ run(Command::new(&zig).args(["cc", "-target", "wasm32-freestanding", "-mcpu=mvp",
25
+ "-Oz", "-std=c99", "-ffreestanding", "-fno-builtin", "-fvisibility=hidden",
26
+ "-I", "freestanding", "-I", "bearssl/inc", "-I", "bearssl/src", "-c"])
27
+ .arg(source).arg("-o").arg(&object));
28
+ objects.push(object);
29
+ }
30
+ let archive = out.join("libpulse_rsa.a");
31
+ run(Command::new(&zig).args(["ar", "rcs"]).arg(&archive).args(objects));
32
+ println!("cargo:rustc-link-search=native={}", out.display());
33
+ println!("cargo:rustc-link-lib=static=pulse_rsa");
34
+ println!("cargo:rerun-if-env-changed=PULSE_RSA_ZIG");
35
+ println!("cargo:rerun-if-changed=rs256.c");
36
+ println!("cargo:rerun-if-changed=bearssl");
37
+ println!("cargo:rerun-if-changed=freestanding");
38
+ }
@@ -0,0 +1,8 @@
1
+ #ifndef PULSE_STRING_H
2
+ #define PULSE_STRING_H
3
+ #include <stddef.h>
4
+ void *memcpy(void *, const void *, size_t);
5
+ void *memmove(void *, const void *, size_t);
6
+ void *memset(void *, int, size_t);
7
+ int memcmp(const void *, const void *, size_t);
8
+ #endif
@@ -0,0 +1,103 @@
1
+ /* Pulse RS256 adapter. RSA arithmetic is BearSSL 0.6's unmodified i31 code.
2
+ * Wire: LE32(k), n[k], e[4], then d[k], p/q/dp/dq/qi[k/2] for signing.
3
+ * All integers are unsigned big endian. Only balanced 2048/3072/4096 keys.
4
+ * No allocation, entropy, host callbacks, or retained pointers.
5
+ */
6
+ #include "inner.h"
7
+
8
+ #define WORDS 136
9
+ static const unsigned char sha256_oid[] = {9, 0x60, 0x86, 0x48, 1, 0x65, 3, 4, 2, 1};
10
+
11
+ static uint32_t equal(const unsigned char *a, const unsigned char *b, size_t n) {
12
+ uint32_t diff = 0;
13
+ for (size_t i = 0; i < n; i++) diff |= a[i] ^ b[i];
14
+ return EQ(diff, 0);
15
+ }
16
+
17
+ /* Use the declared fixed width, including for secret exponents. BearSSL's
18
+ * arithmetic lengths must not depend on their leading zero bits. */
19
+ static void decode(uint32_t *a, const unsigned char *p, size_t n) {
20
+ memset(a, 0, WORDS * sizeof *a);
21
+ br_i31_decode(a, p, n);
22
+ a[0] = (uint32_t)((n * 8 / 31) * 32 + n * 8 % 31);
23
+ }
24
+
25
+ static uint32_t reduced_equal(const uint32_t *a, const uint32_t *m,
26
+ const unsigned char *expected, size_t n) {
27
+ uint32_t r[WORDS] = {0};
28
+ unsigned char encoded[512];
29
+ br_i31_reduce(r, a, m);
30
+ br_i31_encode(encoded, n, r);
31
+ return equal(encoded, expected, n);
32
+ }
33
+
34
+ /* Check n=p*q, d mod (p-1)=dp, d mod (q-1)=dq,
35
+ * e*dp=1 mod (p-1), e*dq=1 mod (q-1), and q*qi=1 mod p.
36
+ * These are consistency checks, not a primality proof/key generation API.
37
+ * Factors have a fixed public width and top bit; no variable-time inverse. */
38
+ static uint32_t private_valid(const unsigned char *key, size_t k) {
39
+ const size_t h = k / 2;
40
+ const unsigned char *n = key + 4, *e = n + k, *d = e + 4;
41
+ const unsigned char *p = d + k, *q = p + h, *dp = q + h;
42
+ const unsigned char *dq = dp + h, *qi = dq + h;
43
+ uint32_t a[WORDS], b[WORDS], product[WORDS], m[WORDS], one[WORDS];
44
+ unsigned char encoded[512], expected[256] = {0};
45
+ uint32_t ok = (p[0] >> 7) & (q[0] >> 7) & (p[h-1] & q[h-1] & 1);
46
+ ok &= 1 ^ equal(p, q, h);
47
+ decode(a, p, h); decode(b, q, h);
48
+ memset(product, 0, sizeof product); product[0] = a[0];
49
+ br_i31_mulacc(product, a, b); br_i31_encode(encoded, k, product);
50
+ ok &= equal(encoded, n, k);
51
+ decode(a, d, k); decode(m, n, k);
52
+ ok &= br_i31_sub(a, m, 0);
53
+ for (size_t i = 0; i < 2; i++) {
54
+ decode(m, i == 0 ? p : q, h);
55
+ memset(one, 0, sizeof one); one[0] = m[0]; one[1] = 1;
56
+ br_i31_sub(m, one, 1);
57
+ decode(a, d, k);
58
+ ok &= reduced_equal(a, m, i == 0 ? dp : dq, h);
59
+ decode(a, i == 0 ? dp : dq, h); decode(b, e, 4);
60
+ memset(product, 0, sizeof product); product[0] = a[0];
61
+ br_i31_mulacc(product, a, b);
62
+ expected[h-1] = 1;
63
+ ok &= reduced_equal(product, m, expected, h);
64
+ }
65
+ decode(m, p, h); decode(a, q, h); decode(b, qi, h);
66
+ /* qi must be the canonical residue, not qi+p. */
67
+ ok &= br_i31_sub(b, m, 0);
68
+ memset(product, 0, sizeof product); product[0] = a[0];
69
+ br_i31_mulacc(product, a, b);
70
+ ok &= reduced_equal(product, m, expected, h);
71
+ return ok;
72
+ }
73
+
74
+ static uint32_t public_valid(const unsigned char *key, size_t k) {
75
+ const unsigned char *e = key + 4 + k;
76
+ uint32_t exponent = br_dec32be(e);
77
+ return (key[4] >> 7) & (key[3+k] & 1) & (exponent & 1) & GT(exponent, 2);
78
+ }
79
+
80
+ int pulse_rs256(const unsigned char *key, size_t key_len, const unsigned char *hash,
81
+ unsigned char *signature, size_t k, int sign) {
82
+ if (!(k == 256 || k == 384 || k == 512)
83
+ || key_len != (sign ? 8 + k * 9 / 2 : 8 + k)
84
+ || br_dec32le(key) != k || !public_valid(key, k)) return -1;
85
+ unsigned char expected[512], actual[512];
86
+ br_rsa_public_key pk = {(unsigned char *)key + 4, k, (unsigned char *)key + 4 + k, 4};
87
+ if (!br_rsa_pkcs1_sig_pad(sha256_oid, hash, 32, (uint32_t)k * 8, expected)) return -2;
88
+ if (sign) {
89
+ if (!private_valid(key, k)) return -1;
90
+ const size_t h = k / 2;
91
+ unsigned char *p = (unsigned char *)key + 8 + 2*k;
92
+ br_rsa_private_key sk = {(uint32_t)k*8, p, h, p+h, h, p+2*h, h, p+3*h, h, p+4*h, h};
93
+ memcpy(actual, expected, k);
94
+ if (!br_rsa_i31_private(actual, &sk)) return -1;
95
+ memcpy(signature, actual, k);
96
+ } else memcpy(actual, signature, k);
97
+ /* Exact EMSA-PKCS1-v1_5 encoding, including NULL AlgorithmIdentifier.
98
+ * Also a fault/CRT check before any private result is released. */
99
+ uint32_t ok = br_rsa_i31_public(actual, k, &pk);
100
+ ok &= equal(actual, expected, k);
101
+ if (sign && !ok) { memset(signature, 0, k); return -1; }
102
+ return (int)ok;
103
+ }
@@ -0,0 +1,5 @@
1
+ [toolchain]
2
+ channel = "1.97.1"
3
+ components = []
4
+ profile = "minimal"
5
+ targets = ["wasm32v1-none"]