aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doxyfile2427
-rw-r--r--LICENSE.txt21
-rw-r--r--Makefile45
-rw-r--r--README.txt136
-rw-r--r--T0/BlobWriter.cs112
-rw-r--r--T0/CPU.cs181
-rw-r--r--T0/CodeElement.cs100
-rw-r--r--T0/CodeElementJump.cs97
-rw-r--r--T0/CodeElementUInt.cs55
-rw-r--r--T0/CodeElementUIntExpr.cs66
-rw-r--r--T0/CodeElementUIntInt.cs61
-rw-r--r--T0/CodeElementUIntUInt.cs60
-rw-r--r--T0/ConstData.cs198
-rw-r--r--T0/Opcode.cs117
-rw-r--r--T0/OpcodeCall.cs71
-rw-r--r--T0/OpcodeConst.cs95
-rw-r--r--T0/OpcodeGetLocal.cs57
-rw-r--r--T0/OpcodeJump.cs64
-rw-r--r--T0/OpcodeJumpIf.cs65
-rw-r--r--T0/OpcodeJumpIfNot.cs65
-rw-r--r--T0/OpcodeJumpUncond.cs61
-rw-r--r--T0/OpcodePutLocal.cs57
-rw-r--r--T0/OpcodeRet.cs50
-rw-r--r--T0/SType.cs129
-rw-r--r--T0/T0Comp.cs2123
-rw-r--r--T0/TPointerBase.cs64
-rw-r--r--T0/TPointerBlob.cs75
-rw-r--r--T0/TPointerExpr.cs97
-rw-r--r--T0/TPointerNull.cs44
-rw-r--r--T0/TPointerXT.cs73
-rw-r--r--T0/TValue.cs231
-rw-r--r--T0/Word.cs172
-rw-r--r--T0/WordBuilder.cs385
-rw-r--r--T0/WordData.cs96
-rw-r--r--T0/WordInterpreted.cs283
-rw-r--r--T0/WordNative.cs59
-rw-r--r--T0/kern.t0309
-rwxr-xr-xT0Comp.exebin0 -> 72704 bytes
-rw-r--r--build/.do_not_remove0
-rw-r--r--conf/Unix.mk69
-rw-r--r--conf/Unix32.mk12
-rw-r--r--conf/UnixClang.mk11
-rw-r--r--conf/Win.mk70
-rw-r--r--conf/samd20.mk20
-rw-r--r--inc/bearssl.h170
-rw-r--r--inc/bearssl_aead.h1059
-rw-r--r--inc/bearssl_block.h2618
-rw-r--r--inc/bearssl_ec.h967
-rw-r--r--inc/bearssl_hash.h1346
-rw-r--r--inc/bearssl_hmac.h241
-rw-r--r--inc/bearssl_kdf.h284
-rw-r--r--inc/bearssl_pem.h294
-rw-r--r--inc/bearssl_prf.h150
-rw-r--r--inc/bearssl_rand.h397
-rw-r--r--inc/bearssl_rsa.h1655
-rw-r--r--inc/bearssl_ssl.h4296
-rw-r--r--inc/bearssl_x509.h1397
-rw-r--r--mk/Defaults.mk41
-rw-r--r--mk/NMake.mk38
-rw-r--r--mk/Rules.mk1318
-rw-r--r--mk/SingleUnix.mk38
-rw-r--r--mk/mkT0.cmd32
-rwxr-xr-xmk/mkT0.sh11
-rwxr-xr-xmk/mkrules.sh570
-rw-r--r--samples/README.txt36
-rw-r--r--samples/cert-ee-ec+rsa.pem14
-rw-r--r--samples/cert-ee-ec.pem10
-rw-r--r--samples/cert-ee-rsa.pem17
-rw-r--r--samples/cert-ica-ec.pem10
-rw-r--r--samples/cert-ica-rsa.pem17
-rw-r--r--samples/cert-root-ec.pem9
-rw-r--r--samples/cert-root-rsa.pem16
-rw-r--r--samples/chain-ec+rsa.h166
-rw-r--r--samples/chain-ec.h117
-rw-r--r--samples/chain-rsa.h183
-rw-r--r--samples/client_basic.c380
-rw-r--r--samples/custom_profile.c601
-rw-r--r--samples/key-ec.h40
-rw-r--r--samples/key-ee-ec.pem5
-rw-r--r--samples/key-ee-rsa.pem23
-rw-r--r--samples/key-ica-ec.pem5
-rw-r--r--samples/key-ica-rsa.pem23
-rw-r--r--samples/key-root-ec.pem5
-rw-r--r--samples/key-root-rsa.pem23
-rw-r--r--samples/key-rsa.h108
-rw-r--r--samples/server_basic.c436
-rw-r--r--src/aead/ccm.c346
-rw-r--r--src/aead/eax.c525
-rw-r--r--src/aead/gcm.c318
-rw-r--r--src/codec/ccopy.c44
-rw-r--r--src/codec/dec16be.c38
-rw-r--r--src/codec/dec16le.c38
-rw-r--r--src/codec/dec32be.c38
-rw-r--r--src/codec/dec32le.c38
-rw-r--r--src/codec/dec64be.c38
-rw-r--r--src/codec/dec64le.c38
-rw-r--r--src/codec/enc16be.c38
-rw-r--r--src/codec/enc16le.c38
-rw-r--r--src/codec/enc32be.c38
-rw-r--r--src/codec/enc32le.c38
-rw-r--r--src/codec/enc64be.c38
-rw-r--r--src/codec/enc64le.c38
-rw-r--r--src/codec/pemdec.c526
-rw-r--r--src/codec/pemdec.t0314
-rw-r--r--src/codec/pemenc.c173
-rw-r--r--src/config.h229
-rw-r--r--src/ec/ec_all_m15.c121
-rw-r--r--src/ec/ec_all_m31.c171
-rw-r--r--src/ec/ec_c25519_i15.c398
-rw-r--r--src/ec/ec_c25519_i31.c390
-rw-r--r--src/ec/ec_c25519_m15.c1478
-rw-r--r--src/ec/ec_c25519_m31.c800
-rw-r--r--src/ec/ec_c25519_m62.c605
-rw-r--r--src/ec/ec_c25519_m64.c835
-rw-r--r--src/ec/ec_curve25519.c46
-rw-r--r--src/ec/ec_default.c36
-rw-r--r--src/ec/ec_keygen.c86
-rw-r--r--src/ec/ec_p256_m15.c2130
-rw-r--r--src/ec/ec_p256_m31.c1475
-rw-r--r--src/ec/ec_p256_m62.c1765
-rw-r--r--src/ec/ec_p256_m64.c1730
-rw-r--r--src/ec/ec_prime_i15.c820
-rw-r--r--src/ec/ec_prime_i31.c819
-rw-r--r--src/ec/ec_pubkey.c85
-rw-r--r--src/ec/ec_secp256r1.c51
-rw-r--r--src/ec/ec_secp384r1.c57
-rw-r--r--src/ec/ec_secp521r1.c64
-rw-r--r--src/ec/ecdsa_atr.c134
-rw-r--r--src/ec/ecdsa_default_sign_asn1.c36
-rw-r--r--src/ec/ecdsa_default_sign_raw.c36
-rw-r--r--src/ec/ecdsa_default_vrfy_asn1.c36
-rw-r--r--src/ec/ecdsa_default_vrfy_raw.c36
-rw-r--r--src/ec/ecdsa_i15_bits.c47
-rw-r--r--src/ec/ecdsa_i15_sign_asn1.c45
-rw-r--r--src/ec/ecdsa_i15_sign_raw.c174
-rw-r--r--src/ec/ecdsa_i15_vrfy_asn1.c48
-rw-r--r--src/ec/ecdsa_i15_vrfy_raw.c166
-rw-r--r--src/ec/ecdsa_i31_bits.c47
-rw-r--r--src/ec/ecdsa_i31_sign_asn1.c45
-rw-r--r--src/ec/ecdsa_i31_sign_raw.c173
-rw-r--r--src/ec/ecdsa_i31_vrfy_asn1.c48
-rw-r--r--src/ec/ecdsa_i31_vrfy_raw.c165
-rw-r--r--src/ec/ecdsa_rta.c121
-rw-r--r--src/hash/dig_oid.c84
-rw-r--r--src/hash/dig_size.c50
-rw-r--r--src/hash/ghash_ctmul.c345
-rw-r--r--src/hash/ghash_ctmul32.c251
-rw-r--r--src/hash/ghash_ctmul64.c154
-rw-r--r--src/hash/ghash_pclmul.c389
-rw-r--r--src/hash/ghash_pwr8.c411
-rw-r--r--src/hash/md5.c208
-rw-r--r--src/hash/md5sha1.c141
-rw-r--r--src/hash/mgf1.c56
-rw-r--r--src/hash/multihash.c166
-rw-r--r--src/hash/sha1.c191
-rw-r--r--src/hash/sha2big.c285
-rw-r--r--src/hash/sha2small.c341
-rw-r--r--src/inner.h2557
-rw-r--r--src/int/i15_add.c46
-rw-r--r--src/int/i15_bitlen.c44
-rw-r--r--src/int/i15_decmod.c124
-rw-r--r--src/int/i15_decode.c56
-rw-r--r--src/int/i15_decred.c100
-rw-r--r--src/int/i15_encode.c56
-rw-r--r--src/int/i15_fmont.c59
-rw-r--r--src/int/i15_iszero.c39
-rw-r--r--src/int/i15_moddiv.c465
-rw-r--r--src/int/i15_modpow.c50
-rw-r--r--src/int/i15_modpow2.c160
-rw-r--r--src/int/i15_montmul.c184
-rw-r--r--src/int/i15_mulacc.c61
-rw-r--r--src/int/i15_muladd.c173
-rw-r--r--src/int/i15_ninv15.c38
-rw-r--r--src/int/i15_reduce.c66
-rw-r--r--src/int/i15_rshift.c47
-rw-r--r--src/int/i15_sub.c46
-rw-r--r--src/int/i15_tmont.c36
-rw-r--r--src/int/i31_add.c46
-rw-r--r--src/int/i31_bitlen.c44
-rw-r--r--src/int/i31_decmod.c124
-rw-r--r--src/int/i31_decode.c57
-rw-r--r--src/int/i31_decred.c103
-rw-r--r--src/int/i31_encode.c79
-rw-r--r--src/int/i31_fmont.c60
-rw-r--r--src/int/i31_iszero.c39
-rw-r--r--src/int/i31_moddiv.c488
-rw-r--r--src/int/i31_modpow.c65
-rw-r--r--src/int/i31_modpow2.c160
-rw-r--r--src/int/i31_montmul.c127
-rw-r--r--src/int/i31_mulacc.c74
-rw-r--r--src/int/i31_muladd.c157
-rw-r--r--src/int/i31_ninv31.c39
-rw-r--r--src/int/i31_reduce.c66
-rw-r--r--src/int/i31_rshift.c47
-rw-r--r--src/int/i31_sub.c46
-rw-r--r--src/int/i31_tmont.c36
-rw-r--r--src/int/i32_add.c51
-rw-r--r--src/int/i32_bitlen.c44
-rw-r--r--src/int/i32_decmod.c77
-rw-r--r--src/int/i32_decode.c63
-rw-r--r--src/int/i32_decred.c107
-rw-r--r--src/int/i32_div32.c56
-rw-r--r--src/int/i32_encode.c72
-rw-r--r--src/int/i32_fmont.c60
-rw-r--r--src/int/i32_iszero.c39
-rw-r--r--src/int/i32_modpow.c65
-rw-r--r--src/int/i32_montmul.c69
-rw-r--r--src/int/i32_mulacc.c56
-rw-r--r--src/int/i32_muladd.c138
-rw-r--r--src/int/i32_ninv32.c39
-rw-r--r--src/int/i32_reduce.c66
-rw-r--r--src/int/i32_sub.c51
-rw-r--r--src/int/i32_tmont.c36
-rw-r--r--src/int/i62_modpow2.c493
-rw-r--r--src/kdf/hkdf.c107
-rw-r--r--src/kdf/shake.c590
-rw-r--r--src/mac/hmac.c122
-rw-r--r--src/mac/hmac_ct.c193
-rw-r--r--src/rand/aesctr_drbg.c206
-rw-r--r--src/rand/hmac_drbg.c157
-rw-r--r--src/rand/sysrng.c170
-rw-r--r--src/rsa/rsa_default_keygen.c38
-rw-r--r--src/rsa/rsa_default_modulus.c36
-rw-r--r--src/rsa/rsa_default_oaep_decrypt.c38
-rw-r--r--src/rsa/rsa_default_oaep_encrypt.c38
-rw-r--r--src/rsa/rsa_default_pkcs1_sign.c38
-rw-r--r--src/rsa/rsa_default_pkcs1_vrfy.c38
-rw-r--r--src/rsa/rsa_default_priv.c38
-rw-r--r--src/rsa/rsa_default_privexp.c36
-rw-r--r--src/rsa/rsa_default_pss_sign.c38
-rw-r--r--src/rsa/rsa_default_pss_vrfy.c38
-rw-r--r--src/rsa/rsa_default_pub.c38
-rw-r--r--src/rsa/rsa_default_pubexp.c36
-rw-r--r--src/rsa/rsa_i15_keygen.c583
-rw-r--r--src/rsa/rsa_i15_modulus.c99
-rw-r--r--src/rsa/rsa_i15_oaep_decrypt.c41
-rw-r--r--src/rsa/rsa_i15_oaep_encrypt.c44
-rw-r--r--src/rsa/rsa_i15_pkcs1_sign.c37
-rw-r--r--src/rsa/rsa_i15_pkcs1_vrfy.c43
-rw-r--r--src/rsa/rsa_i15_priv.c209
-rw-r--r--src/rsa/rsa_i15_privexp.c320
-rw-r--r--src/rsa/rsa_i15_pss_sign.c40
-rw-r--r--src/rsa/rsa_i15_pss_vrfy.c44
-rw-r--r--src/rsa/rsa_i15_pub.c113
-rw-r--r--src/rsa/rsa_i15_pubexp.c152
-rw-r--r--src/rsa/rsa_i31_keygen.c37
-rw-r--r--src/rsa/rsa_i31_keygen_inner.c608
-rw-r--r--src/rsa/rsa_i31_modulus.c99
-rw-r--r--src/rsa/rsa_i31_oaep_decrypt.c41
-rw-r--r--src/rsa/rsa_i31_oaep_encrypt.c44
-rw-r--r--src/rsa/rsa_i31_pkcs1_sign.c37
-rw-r--r--src/rsa/rsa_i31_pkcs1_vrfy.c43
-rw-r--r--src/rsa/rsa_i31_priv.c203
-rw-r--r--src/rsa/rsa_i31_privexp.c318
-rw-r--r--src/rsa/rsa_i31_pss_sign.c40
-rw-r--r--src/rsa/rsa_i31_pss_vrfy.c44
-rw-r--r--src/rsa/rsa_i31_pub.c106
-rw-r--r--src/rsa/rsa_i31_pubexp.c152
-rw-r--r--src/rsa/rsa_i32_oaep_decrypt.c41
-rw-r--r--src/rsa/rsa_i32_oaep_encrypt.c44
-rw-r--r--src/rsa/rsa_i32_pkcs1_sign.c37
-rw-r--r--src/rsa/rsa_i32_pkcs1_vrfy.c43
-rw-r--r--src/rsa/rsa_i32_priv.c160
-rw-r--r--src/rsa/rsa_i32_pss_sign.c40
-rw-r--r--src/rsa/rsa_i32_pss_vrfy.c44
-rw-r--r--src/rsa/rsa_i32_pub.c77
-rw-r--r--src/rsa/rsa_i62_keygen.c57
-rw-r--r--src/rsa/rsa_i62_oaep_decrypt.c61
-rw-r--r--src/rsa/rsa_i62_oaep_encrypt.c64
-rw-r--r--src/rsa/rsa_i62_pkcs1_sign.c57
-rw-r--r--src/rsa/rsa_i62_pkcs1_vrfy.c63
-rw-r--r--src/rsa/rsa_i62_priv.c223
-rw-r--r--src/rsa/rsa_i62_pss_sign.c60
-rw-r--r--src/rsa/rsa_i62_pss_vrfy.c64
-rw-r--r--src/rsa/rsa_i62_pub.c125
-rw-r--r--src/rsa/rsa_oaep_pad.c112
-rw-r--r--src/rsa/rsa_oaep_unpad.c145
-rw-r--r--src/rsa/rsa_pkcs1_sig_pad.c100
-rw-r--r--src/rsa/rsa_pkcs1_sig_unpad.c121
-rw-r--r--src/rsa/rsa_pss_sig_pad.c106
-rw-r--r--src/rsa/rsa_pss_sig_unpad.c121
-rw-r--r--src/rsa/rsa_ssl_decrypt.c52
-rw-r--r--src/settings.c306
-rw-r--r--src/ssl/prf.c73
-rw-r--r--src/ssl/prf_md5sha1.c43
-rw-r--r--src/ssl/prf_sha256.c36
-rw-r--r--src/ssl/prf_sha384.c36
-rw-r--r--src/ssl/ssl_ccert_single_ec.c156
-rw-r--r--src/ssl/ssl_ccert_single_rsa.c149
-rw-r--r--src/ssl/ssl_client.c78
-rw-r--r--src/ssl/ssl_client_default_rsapub.c32
-rw-r--r--src/ssl/ssl_client_full.c179
-rw-r--r--src/ssl/ssl_engine.c1569
-rw-r--r--src/ssl/ssl_engine_default_aescbc.c64
-rw-r--r--src/ssl/ssl_engine_default_aesccm.c67
-rw-r--r--src/ssl/ssl_engine_default_aesgcm.c89
-rw-r--r--src/ssl/ssl_engine_default_chapol.c65
-rw-r--r--src/ssl/ssl_engine_default_descbc.c37
-rw-r--r--src/ssl/ssl_engine_default_ec.c36
-rw-r--r--src/ssl/ssl_engine_default_ecdsa.c38
-rw-r--r--src/ssl/ssl_engine_default_rsavrfy.c32
-rw-r--r--src/ssl/ssl_hashes.c46
-rw-r--r--src/ssl/ssl_hs_client.c1915
-rw-r--r--src/ssl/ssl_hs_client.t01276
-rw-r--r--src/ssl/ssl_hs_common.t01382
-rw-r--r--src/ssl/ssl_hs_server.c2009
-rw-r--r--src/ssl/ssl_hs_server.t01510
-rw-r--r--src/ssl/ssl_io.c261
-rw-r--r--src/ssl/ssl_keyexport.c83
-rw-r--r--src/ssl/ssl_lru.c537
-rw-r--r--src/ssl/ssl_rec_cbc.c440
-rw-r--r--src/ssl/ssl_rec_ccm.c213
-rw-r--r--src/ssl/ssl_rec_chapol.c177
-rw-r--r--src/ssl/ssl_rec_gcm.c235
-rw-r--r--src/ssl/ssl_scert_single_ec.c142
-rw-r--r--src/ssl/ssl_scert_single_rsa.c162
-rw-r--r--src/ssl/ssl_server.c52
-rw-r--r--src/ssl/ssl_server_full_ec.c149
-rw-r--r--src/ssl/ssl_server_full_rsa.c132
-rw-r--r--src/ssl/ssl_server_mine2c.c71
-rw-r--r--src/ssl/ssl_server_mine2g.c71
-rw-r--r--src/ssl/ssl_server_minf2c.c71
-rw-r--r--src/ssl/ssl_server_minf2g.c71
-rw-r--r--src/ssl/ssl_server_minr2g.c70
-rw-r--r--src/ssl/ssl_server_minu2g.c70
-rw-r--r--src/ssl/ssl_server_minv2g.c70
-rw-r--r--src/symcipher/aes_big_cbcdec.c69
-rw-r--r--src/symcipher/aes_big_cbcenc.c67
-rw-r--r--src/symcipher/aes_big_ctr.c84
-rw-r--r--src/symcipher/aes_big_ctrcbc.c142
-rw-r--r--src/symcipher/aes_big_dec.c254
-rw-r--r--src/symcipher/aes_big_enc.c157
-rw-r--r--src/symcipher/aes_common.c112
-rw-r--r--src/symcipher/aes_ct.c328
-rw-r--r--src/symcipher/aes_ct64.c398
-rw-r--r--src/symcipher/aes_ct64_cbcdec.c104
-rw-r--r--src/symcipher/aes_ct64_cbcenc.c81
-rw-r--r--src/symcipher/aes_ct64_ctr.c114
-rw-r--r--src/symcipher/aes_ct64_ctrcbc.c433
-rw-r--r--src/symcipher/aes_ct64_dec.c159
-rw-r--r--src/symcipher/aes_ct64_enc.c115
-rw-r--r--src/symcipher/aes_ct_cbcdec.c111
-rw-r--r--src/symcipher/aes_ct_cbcenc.c91
-rw-r--r--src/symcipher/aes_ct_ctr.c116
-rw-r--r--src/symcipher/aes_ct_ctrcbc.c422
-rw-r--r--src/symcipher/aes_ct_dec.c170
-rw-r--r--src/symcipher/aes_ct_enc.c112
-rw-r--r--src/symcipher/aes_pwr8.c445
-rw-r--r--src/symcipher/aes_pwr8_cbcdec.c670
-rw-r--r--src/symcipher/aes_pwr8_cbcenc.c417
-rw-r--r--src/symcipher/aes_pwr8_ctr.c717
-rw-r--r--src/symcipher/aes_pwr8_ctrcbc.c946
-rw-r--r--src/symcipher/aes_small_cbcdec.c69
-rw-r--r--src/symcipher/aes_small_cbcenc.c67
-rw-r--r--src/symcipher/aes_small_ctr.c84
-rw-r--r--src/symcipher/aes_small_ctrcbc.c142
-rw-r--r--src/symcipher/aes_small_dec.c176
-rw-r--r--src/symcipher/aes_small_enc.c129
-rw-r--r--src/symcipher/aes_x86ni.c240
-rw-r--r--src/symcipher/aes_x86ni_cbcdec.c223
-rw-r--r--src/symcipher/aes_x86ni_cbcenc.c122
-rw-r--r--src/symcipher/aes_x86ni_ctr.c211
-rw-r--r--src/symcipher/aes_x86ni_ctrcbc.c596
-rw-r--r--src/symcipher/chacha20_ct.c106
-rw-r--r--src/symcipher/chacha20_sse2.c237
-rw-r--r--src/symcipher/des_ct.c411
-rw-r--r--src/symcipher/des_ct_cbcdec.c87
-rw-r--r--src/symcipher/des_ct_cbcenc.c69
-rw-r--r--src/symcipher/des_support.c166
-rw-r--r--src/symcipher/des_tab.c310
-rw-r--r--src/symcipher/des_tab_cbcdec.c85
-rw-r--r--src/symcipher/des_tab_cbcenc.c67
-rw-r--r--src/symcipher/poly1305_ctmul.c260
-rw-r--r--src/symcipher/poly1305_ctmul32.c297
-rw-r--r--src/symcipher/poly1305_ctmulq.c475
-rw-r--r--src/symcipher/poly1305_i15.c221
-rw-r--r--src/x509/asn1.t0757
-rw-r--r--src/x509/asn1enc.c93
-rw-r--r--src/x509/encode_ec_pk8der.c110
-rw-r--r--src/x509/encode_ec_rawder.c161
-rw-r--r--src/x509/encode_rsa_pk8der.c97
-rw-r--r--src/x509/encode_rsa_rawder.c96
-rw-r--r--src/x509/skey_decoder.c650
-rw-r--r--src/x509/skey_decoder.t0373
-rw-r--r--src/x509/x509_decoder.c773
-rw-r--r--src/x509/x509_decoder.t0321
-rw-r--r--src/x509/x509_knownkey.c105
-rw-r--r--src/x509/x509_minimal.c1713
-rw-r--r--src/x509/x509_minimal.t01508
-rw-r--r--src/x509/x509_minimal_full.c59
-rw-r--r--test/test_crypto.c9475
-rw-r--r--test/test_math.c482
-rw-r--r--test/test_speed.c1772
-rw-r--r--test/test_x509.c2058
-rw-r--r--test/x509/alltests.txt722
-rw-r--r--test/x509/dn-ee.der1
-rw-r--r--test/x509/dn-ica1.der1
-rw-r--r--test/x509/dn-ica2.der1
-rw-r--r--test/x509/dn-root-new.der1
-rw-r--r--test/x509/dn-root.der1
-rw-r--r--test/x509/ee-badsig1.crtbin0 -> 870 bytes
-rw-r--r--test/x509/ee-badsig2.crtbin0 -> 870 bytes
-rw-r--r--test/x509/ee-cp1.crtbin0 -> 745 bytes
-rw-r--r--test/x509/ee-cp2.crtbin0 -> 702 bytes
-rw-r--r--test/x509/ee-cp3.crtbin0 -> 737 bytes
-rw-r--r--test/x509/ee-cp4.crtbin0 -> 748 bytes
-rw-r--r--test/x509/ee-dates.crtbin0 -> 872 bytes
-rw-r--r--test/x509/ee-md5.crtbin0 -> 870 bytes
-rw-r--r--test/x509/ee-names.crtbin0 -> 892 bytes
-rw-r--r--test/x509/ee-names2.crtbin0 -> 842 bytes
-rw-r--r--test/x509/ee-names3.crtbin0 -> 843 bytes
-rw-r--r--test/x509/ee-names4.crtbin0 -> 938 bytes
-rw-r--r--test/x509/ee-p256-sha1.crtbin0 -> 472 bytes
-rw-r--r--test/x509/ee-p256-sha224.crtbin0 -> 473 bytes
-rw-r--r--test/x509/ee-p256-sha256.crtbin0 -> 474 bytes
-rw-r--r--test/x509/ee-p256-sha384.crtbin0 -> 475 bytes
-rw-r--r--test/x509/ee-p256-sha512.crtbin0 -> 474 bytes
-rw-r--r--test/x509/ee-p256.crtbin0 -> 474 bytes
-rw-r--r--test/x509/ee-p384.crtbin0 -> 534 bytes
-rw-r--r--test/x509/ee-p521.crtbin0 -> 610 bytes
-rw-r--r--test/x509/ee-sha1.crtbin0 -> 870 bytes
-rw-r--r--test/x509/ee-sha224.crtbin0 -> 870 bytes
-rw-r--r--test/x509/ee-sha384.crtbin0 -> 870 bytes
-rw-r--r--test/x509/ee-sha512.crtbin0 -> 870 bytes
-rw-r--r--test/x509/ee-trailing.crtbin0 -> 871 bytes
-rw-r--r--test/x509/ee.crtbin0 -> 870 bytes
-rw-r--r--test/x509/ica1-1016.crtbin0 -> 709 bytes
-rw-r--r--test/x509/ica1-1017.crtbin0 -> 709 bytes
-rw-r--r--test/x509/ica1-4096.crtbin0 -> 1098 bytes
-rw-r--r--test/x509/ica1-p256.crtbin0 -> 446 bytes
-rw-r--r--test/x509/ica1-p384.crtbin0 -> 507 bytes
-rw-r--r--test/x509/ica1-p521.crtbin0 -> 581 bytes
-rw-r--r--test/x509/ica1.crtbin0 -> 842 bytes
-rw-r--r--test/x509/ica2-1016.crtbin0 -> 725 bytes
-rw-r--r--test/x509/ica2-1017.crtbin0 -> 726 bytes
-rw-r--r--test/x509/ica2-4096.crtbin0 -> 1111 bytes
-rw-r--r--test/x509/ica2-notCA.crtbin0 -> 852 bytes
-rw-r--r--test/x509/ica2-p256.crtbin0 -> 460 bytes
-rw-r--r--test/x509/ica2-p384.crtbin0 -> 520 bytes
-rw-r--r--test/x509/ica2-p521.crtbin0 -> 595 bytes
-rw-r--r--test/x509/ica2.crtbin0 -> 855 bytes
-rw-r--r--test/x509/junk.crtbin0 -> 800 bytes
-rw-r--r--test/x509/names.crtbin0 -> 1366 bytes
-rw-r--r--test/x509/root-p256.crtbin0 -> 413 bytes
-rw-r--r--test/x509/root-p384.crtbin0 -> 475 bytes
-rw-r--r--test/x509/root-p521.crtbin0 -> 549 bytes
-rw-r--r--test/x509/root.crtbin0 -> 810 bytes
-rw-r--r--tools/brssl.c122
-rw-r--r--tools/brssl.h567
-rw-r--r--tools/certs.c237
-rw-r--r--tools/chain.c154
-rw-r--r--tools/client.c1112
-rw-r--r--tools/errors.c344
-rw-r--r--tools/files.c329
-rw-r--r--tools/impl.c48
-rw-r--r--tools/keys.c234
-rw-r--r--tools/names.c1056
-rw-r--r--tools/server.c1235
-rw-r--r--tools/skey.c784
-rw-r--r--tools/sslio.c760
-rw-r--r--tools/ta.c254
-rw-r--r--tools/twrch.c1069
-rw-r--r--tools/vector.c66
-rw-r--r--tools/verify.c353
-rw-r--r--tools/xmem.c120
465 files changed, 120584 insertions, 0 deletions
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 000000000000..088682db878e
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,2427 @@
+# Doxyfile 1.8.11
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "BearSSL"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = apidoc
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = NO
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = YES
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = NO
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = inc/bearssl.h inc/bearssl_aead.h inc/bearssl_block.h inc/bearssl_ec.h inc/bearssl_hash.h inc/bearssl_hmac.h inc/bearssl_kdf.h inc/bearssl_pem.h inc/bearssl_prf.h inc/bearssl_rand.h inc/bearssl_rsa.h inc/bearssl_ssl.h inc/bearssl_x509.h
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl,
+# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js.
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse-libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX = br_ BR_
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 45
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 150
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED = BR_DOXYGEN_IGNORE
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = NO
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = NO
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = NO
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = NO
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 000000000000..088502032e43
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,21 @@
+Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 000000000000..f7f24fccd1c7
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,45 @@
+# Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+# ======================================================================
+
+# The lines below are a horrible hack that nonetheless works. On a
+# "make" utility compatible with Single Unix v4 (this includes GNU and
+# BSD make), the '\' at the end of a command line counts as an escape
+# for the newline character, so the next line is still a comment.
+# However, Microsoft's nmake.exe (that comes with Visual Studio) does
+# not interpret the final '\' that way in a comment. The end result is
+# that when using nmake.exe, this will include "mk/Win.mk", whereas
+# GNU/BSD make will include "mk/Unix.mk".
+
+# \
+!ifndef 0 # \
+!include mk/NMake.mk # \
+!else
+.POSIX:
+include mk/SingleUnix.mk
+# Extra hack for OpenBSD make.
+ifndef: all
+0: all
+endif: all
+# \
+!endif
diff --git a/README.txt b/README.txt
new file mode 100644
index 000000000000..0cb528874066
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,136 @@
+# Documentation
+
+The most up-to-date documentation is supposed to be available on the
+[BearSSL Web site](https://www.bearssl.org/).
+
+# Disclaimer
+
+BearSSL is considered beta-level software. Most planned functionalities
+are implemented; new evolution may still break both source and binary
+compatibility.
+
+Using BearSSL for production purposes would be a relatively bold but not
+utterly crazy move. BearSSL is free, open-source software, provided
+without any guarantee of fitness or reliability. That being said, it
+appears to behave properly, and only minor issues have been found (and
+fixed) so far. You are encourage to inspect its API and code for
+learning, testing and possibly contributing.
+
+The usage license is explicited in the `LICENSE.txt` file. This is the
+"MIT license". It can be summarised in the following way:
+
+ - You can use and reuse the library as you wish, and modify it, and
+ integrate it in your own code, and distribute it as is or in any
+ modified form, and so on.
+
+ - The only obligation that the license terms put upon you is that you
+ acknowledge and make it clear that if anything breaks, it is not my
+ fault, and I am not liable for anything, regardless of the type and
+ amount of collateral damage. The license terms say that the copyright
+ notice "shall be included in all copies or substantial portions of
+ the Software": this is how the disclaimer is "made explicit".
+ Basically, I have put it in every source file, so just keep it there.
+
+# Installation
+
+Right now, BearSSL is a simple library, along with a few test and debug
+command-line tools. There is no installer yet. The library _can_ be
+compiled as a shared library on some systems, but since the binary API
+is not fully stabilised, this is not a very good idea to do that right
+now.
+
+To compile the code, just type `make`. This will try to use sane
+"default" values. On a Windows system with Visual Studio, run a console
+with the environment initialised for a specific version of the C compiler,
+and type `nmake`.
+
+To override the default settings, create a custom configuration file in
+the `conf` directory, and invoke `make` (or `nmake`) with an explicit
+`CONF=` parameter. For instance, to use the provided `samd20.mk`
+configuration file (that targets cross-compilation for an Atmel board
+that features a Cortex-M0+ CPU), type:
+
+ make CONF=samd20
+
+The `conf/samd20.mk` file includes the `Unix.mk` file and then overrides
+some of the parameters, including the destination directory. Any custom
+configuration can be made the same way.
+
+Some compile-time options can be set through macros, either on the
+compiler command-line, or in the `src/config.h` file. See the comments
+in that file. Some settings are autodetected but they can still be
+explicitly overridden.
+
+When compilation is done, the library (static and DLL, when appropriate)
+and the command-line tools can be found in the designated build
+directory (by default named `build`). The public headers (to be used
+by applications linked against BearSSL) are in the `inc/` directory.
+
+To run the tests:
+
+ - `testcrypto all` runs the cryptographic tests (test vectors on all
+ implemented cryptogaphic functions). It can be slow. You can also
+ run a selection of the tests by providing their names (run
+ `testcrypto` without any parameter to see the available names).
+
+ - `testspeed all` runs a number of performance benchmarks, there again
+ on cryptographic functions. It gives a taste of how things go on the
+ current platform. As for `testcrypto`, specific named benchmarks can
+ be executed.
+
+ - `testx509` runs X.509 validation tests. The test certificates are
+ all in `test/x509/`.
+
+The `brssl` command-line tool produced in the build directory is a
+stand-alone binary. It can exercise some of the functionalities of
+BearSSL, in particular running a test SSL client or server. It is not
+meant for production purposes (e.g. the SSL client has a mode where it
+disregards the inability to validate the server's certificate, which is
+inherently unsafe, but convenient for debug).
+
+**Using the library** means writing some application code that invokes
+it, and linking with the static library. The header files are all in the
+`inc` directory; copy them wherever makes sense (e.g. in the
+`/usr/local/include` directory). The library itself (`libbearssl.a`) is
+what you link against.
+
+Alternatively, you may want to copy the source files directly into your
+own application code. This will make integrating ulterior versions of
+BearSSL more difficult. If you still want to go down that road, then
+simply copy all the `*.h` and `*.c` files from the `src` and `inc`
+directories into your application source code. In the BearSSL source
+archive, the source files are segregated into various sub-directories,
+but this is for my convenience only. There is no technical requirement
+for that, and all files can be dumped together in a simple directory.
+
+Dependencies are simple and systematic:
+
+ - Each `*.c` file includes `inner.h`
+ - `inner.h` includes `config.h` and `bearssl.h`
+ - `bearssl.h` includes the other `bearssl_*.h`
+
+# Versioning
+
+I follow this simple version numbering scheme:
+
+ - Version numbers are `x.y` or `x.y.z` where `x`, `y` and `z` are
+ decimal integers (possibly greater than 10). When the `.z` part is
+ missing, it is equivalent to `.0`.
+
+ - Backward compatibility is maintained, at both source and binary levels,
+ for each major version: this means that if some application code was
+ designed for version `x.y`, then it should compile, link and run
+ properly with any version `x.y'` for any `y'` greater than `y`.
+
+ The major version `0` is an exception. You shall not expect that any
+ version that starts with `0.` offers any kind of compatibility,
+ either source or binary, with any other `0.` version. (Of course I
+ will try to maintain some decent level of source compatibility, but I
+ make no promise in that respect. Since the API uses caller-allocated
+ context structures, I already know that binary compatibility _will_
+ be broken.)
+
+ - Sub-versions (the `y` part) are about added functionality. That is,
+ it can be expected that `1.3` will contain some extra functions when
+ compared to `1.2`. The next version level (the `z` part) is for
+ bugfixes that do not add any functionality.
diff --git a/T0/BlobWriter.cs b/T0/BlobWriter.cs
new file mode 100644
index 000000000000..3bbc8e6ac29f
--- /dev/null
+++ b/T0/BlobWriter.cs
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.IO;
+using System.Text;
+
+/*
+ * A simple class for writing out bytes as hexadecimal constants or
+ * explicit expressions for the initializer of a C array of 'unsigned
+ * char'. It starts every line with a given number of tabs, and aims at
+ * keeping lines below a given threshold (each indentation tab counts as
+ * 8 characters). An explicit newline is inserted before the first
+ * element, and commas are used as separators.
+ */
+
+class BlobWriter {
+
+ TextWriter w;
+ int maxLineLen;
+ int indent;
+ int lineLen;
+
+ /*
+ * Create a new instance. 'maxLineLen' is in characters, and
+ * 'indent' is the number of tab characters at the start of
+ * each line.
+ */
+ internal BlobWriter(TextWriter w, int maxLineLen, int indent)
+ {
+ this.w = w;
+ this.maxLineLen = maxLineLen;
+ this.indent = indent;
+ lineLen = -1;
+ }
+
+ void DoNL()
+ {
+ w.WriteLine();
+ for (int i = 0; i < indent; i ++) {
+ w.Write('\t');
+ }
+ lineLen = (indent << 3);
+ }
+
+ /*
+ * Append a new byte value; it will be converted to an hexadecimal
+ * constant in the output.
+ */
+ internal void Append(byte b)
+ {
+ if (lineLen < 0) {
+ DoNL();
+ } else {
+ w.Write(',');
+ lineLen ++;
+ if ((lineLen + 5) > maxLineLen) {
+ DoNL();
+ } else {
+ w.Write(' ');
+ lineLen ++;
+ }
+ }
+ w.Write("0x{0:X2}", b);
+ lineLen += 4;
+ }
+
+ /*
+ * Append a C expression, which will be used as is. The expression
+ * may resolve to several bytes if it uses internal commas. The
+ * writer will try to honour the expected line length, but it
+ * won't insert a newline character inside the expression.
+ */
+ internal void Append(string expr)
+ {
+ if (lineLen < 0) {
+ DoNL();
+ } else {
+ w.Write(',');
+ lineLen ++;
+ if ((lineLen + 1 + expr.Length) > maxLineLen) {
+ DoNL();
+ } else {
+ w.Write(' ');
+ lineLen ++;
+ }
+ }
+ w.Write("{0}", expr);
+ lineLen += expr.Length;
+ }
+}
diff --git a/T0/CPU.cs b/T0/CPU.cs
new file mode 100644
index 000000000000..22f1a1793aad
--- /dev/null
+++ b/T0/CPU.cs
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+/*
+ * Execution of code during compilation is done in a virtual CPU
+ * incarnated by this class, that contains the relevant registers.
+ *
+ * Accesses to the data on the stack are mapped to accesses to an
+ * internal array, with no explicit control on boundaries. Since the
+ * internal array may be larger than the actual stack contents,
+ * nonsensical accesses may still "work" to some extent. The whole
+ * thing won't derail beyond the CLR VM, though.
+ */
+
+class CPU {
+
+ /*
+ * Next instruction to execute is in ipBuf[ipOff].
+ */
+ internal Opcode[] ipBuf;
+ internal int ipOff;
+
+ /*
+ * stackBuf and stackPtr implement the data stack. The system
+ * stack uses frames; 'rsp' points to the current top frame.
+ */
+ TValue[] stackBuf;
+ int stackPtr;
+ Frame rsp;
+
+ internal CPU()
+ {
+ stackBuf = new TValue[16];
+ stackPtr = -1;
+ rsp = null;
+ }
+
+ /*
+ * Enter a function, reserving space for 'numLocals' local variables.
+ */
+ internal void Enter(Opcode[] code, int numLocals)
+ {
+ Frame f = new Frame(rsp, numLocals);
+ rsp = f;
+ f.savedIpBuf = ipBuf;
+ f.savedIpOff = ipOff;
+ ipBuf = code;
+ ipOff = 0;
+ }
+
+ /*
+ * Exit the current function.
+ */
+ internal void Exit()
+ {
+ ipBuf = rsp.savedIpBuf;
+ ipOff = rsp.savedIpOff;
+ rsp = rsp.upper;
+ }
+
+ /*
+ * Get the current stack depth (number of elements).
+ */
+ internal int Depth {
+ get {
+ return stackPtr + 1;
+ }
+ }
+
+ /*
+ * Pop a value from the stack.
+ */
+ internal TValue Pop()
+ {
+ return stackBuf[stackPtr --];
+ }
+
+ /*
+ * Push a value on the stack.
+ */
+ internal void Push(TValue v)
+ {
+ int len = stackBuf.Length;
+ if (++ stackPtr == len) {
+ TValue[] nbuf = new TValue[len << 1];
+ Array.Copy(stackBuf, 0, nbuf, 0, len);
+ stackBuf = nbuf;
+ }
+ stackBuf[stackPtr] = v;
+ }
+
+ /*
+ * Look at the value at depth 'depth' (0 is top of stack). The
+ * stack is unchanged.
+ */
+ internal TValue Peek(int depth)
+ {
+ return stackBuf[stackPtr - depth];
+ }
+
+ /*
+ * Rotate the stack at depth 'depth': the value at that depth
+ * is moved to the top of stack.
+ */
+ internal void Rot(int depth)
+ {
+ TValue v = stackBuf[stackPtr - depth];
+ Array.Copy(stackBuf, stackPtr - (depth - 1),
+ stackBuf, stackPtr - depth, depth);
+ stackBuf[stackPtr] = v;
+ }
+
+ /*
+ * Inverse-rotate the stack at depth 'depth': the value at the
+ * top of stack is moved to that depth.
+ */
+ internal void NRot(int depth)
+ {
+ TValue v = stackBuf[stackPtr];
+ Array.Copy(stackBuf, stackPtr - depth,
+ stackBuf, stackPtr - (depth - 1), depth);
+ stackBuf[stackPtr - depth] = v;
+ }
+
+ /*
+ * Get the current contents of the local variable 'num'.
+ */
+ internal TValue GetLocal(int num)
+ {
+ return rsp.locals[num];
+ }
+
+ /*
+ * Set the contents of the local variable 'num'.
+ */
+ internal void PutLocal(int num, TValue v)
+ {
+ rsp.locals[num] = v;
+ }
+
+ /*
+ * The system stack really is a linked list of Frame instances.
+ */
+ class Frame {
+
+ internal Frame upper;
+ internal Opcode[] savedIpBuf;
+ internal int savedIpOff;
+ internal TValue[] locals;
+
+ internal Frame(Frame upper, int numLocals)
+ {
+ this.upper = upper;
+ locals = new TValue[numLocals];
+ }
+ }
+}
diff --git a/T0/CodeElement.cs b/T0/CodeElement.cs
new file mode 100644
index 000000000000..471a61f903f2
--- /dev/null
+++ b/T0/CodeElement.cs
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+
+abstract class CodeElement {
+
+ internal int Address { get; set; }
+
+ internal int LastLength { get; set; }
+
+ // internal abstract int Length { get; }
+
+ internal CodeElement()
+ {
+ Address = -1;
+ }
+
+ internal virtual void SetJumpTarget(CodeElement target)
+ {
+ throw new Exception("Code element accepts no target");
+ }
+
+ internal abstract int GetLength(bool oneByteCode);
+
+ internal abstract int Encode(BlobWriter bw, bool oneByteCode);
+
+ internal static int EncodeOneByte(uint val, BlobWriter bw)
+ {
+ if (val > 255) {
+ throw new Exception(string.Format(
+ "Cannot encode '{0}' over one byte", val));
+ }
+ bw.Append((byte)val);
+ return 1;
+ }
+
+ internal static int Encode7EUnsigned(uint val, BlobWriter bw)
+ {
+ int len = 1;
+ for (uint w = val; w >= 0x80; w >>= 7) {
+ len ++;
+ }
+ if (bw != null) {
+ for (int k = (len - 1) * 7; k >= 0; k -= 7) {
+ int x = (int)(val >> k) & 0x7F;
+ if (k > 0) {
+ x |= 0x80;
+ }
+ bw.Append((byte)x);
+ }
+ }
+ return len;
+ }
+
+ internal static int Encode7ESigned(int val, BlobWriter bw)
+ {
+ int len = 1;
+ if (val < 0) {
+ for (int w = val; w < -0x40; w >>= 7) {
+ len ++;
+ }
+ } else {
+ for (int w = val; w >= 0x40; w >>= 7) {
+ len ++;
+ }
+ }
+ if (bw != null) {
+ for (int k = (len - 1) * 7; k >= 0; k -= 7) {
+ int x = (int)(val >> k) & 0x7F;
+ if (k > 0) {
+ x |= 0x80;
+ }
+ bw.Append((byte)x);
+ }
+ }
+ return len;
+ }
+}
diff --git a/T0/CodeElementJump.cs b/T0/CodeElementJump.cs
new file mode 100644
index 000000000000..4dae0bc8c059
--- /dev/null
+++ b/T0/CodeElementJump.cs
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+
+class CodeElementJump : CodeElement {
+
+ uint jumpType;
+ CodeElement target;
+
+ internal CodeElementJump(uint jumpType)
+ {
+ this.jumpType = jumpType;
+ }
+
+ /* obsolete
+ internal override int Length {
+ get {
+ int len = Encode7EUnsigned(jumpType, null);
+ int joff = JumpOff;
+ if (joff == Int32.MinValue) {
+ len ++;
+ } else {
+ len += Encode7ESigned(joff, null);
+ }
+ return len;
+ }
+ }
+ */
+
+ internal override int GetLength(bool oneByteCode)
+ {
+ int len = oneByteCode ? 1 : Encode7EUnsigned(jumpType, null);
+ int joff = JumpOff;
+ if (joff == Int32.MinValue) {
+ len ++;
+ } else {
+ len += Encode7ESigned(joff, null);
+ }
+ return len;
+ }
+
+ internal override void SetJumpTarget(CodeElement target)
+ {
+ this.target = target;
+ }
+
+ int JumpOff {
+ get {
+ if (target == null || Address < 0 || target.Address < 0)
+ {
+ return Int32.MinValue;
+ } else {
+ return target.Address - (Address + LastLength);
+ }
+ }
+ }
+
+ internal override int Encode(BlobWriter bw, bool oneByteCode)
+ {
+ if (bw == null) {
+ return GetLength(oneByteCode);
+ }
+ int len;
+ if (oneByteCode) {
+ len = EncodeOneByte(jumpType, bw);
+ } else {
+ len = Encode7EUnsigned(jumpType, bw);
+ }
+ int joff = JumpOff;
+ if (joff == Int32.MinValue) {
+ throw new Exception("Unresolved addresses");
+ }
+ return len + Encode7ESigned(joff, bw);
+ }
+}
diff --git a/T0/CodeElementUInt.cs b/T0/CodeElementUInt.cs
new file mode 100644
index 000000000000..049cdad642e1
--- /dev/null
+++ b/T0/CodeElementUInt.cs
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+
+class CodeElementUInt : CodeElement {
+
+ uint val;
+
+ internal CodeElementUInt(uint val) : base()
+ {
+ this.val = val;
+ }
+
+ /* obsolete
+ internal override int Length {
+ get {
+ return Encode7EUnsigned(val, null);
+ }
+ }
+ */
+
+ internal override int GetLength(bool oneByteCode)
+ {
+ return oneByteCode ? 1 : Encode7EUnsigned(val, null);
+ }
+
+ internal override int Encode(BlobWriter bw, bool oneByteCode)
+ {
+ return oneByteCode
+ ? EncodeOneByte(val, bw)
+ : Encode7EUnsigned(val, bw);
+ }
+}
diff --git a/T0/CodeElementUIntExpr.cs b/T0/CodeElementUIntExpr.cs
new file mode 100644
index 000000000000..8dd55a54d953
--- /dev/null
+++ b/T0/CodeElementUIntExpr.cs
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+
+class CodeElementUIntExpr : CodeElement {
+
+ uint val;
+ TPointerExpr cx;
+ int off;
+
+ internal CodeElementUIntExpr(uint val,
+ TPointerExpr cx, int off) : base()
+ {
+ this.val = val;
+ this.cx = cx;
+ this.off = off;
+ }
+
+ /* obsolete
+ internal override int Length {
+ get {
+ return Encode7EUnsigned(val, null)
+ + (cx.GetMaxBitLength(off) + 6) / 7;
+ }
+ }
+ */
+
+ internal override int GetLength(bool oneByteCode)
+ {
+ int len = oneByteCode ? 1 : Encode7EUnsigned(val, null);
+ return len + (cx.GetMaxBitLength(off) + 6) / 7;
+ }
+
+ internal override int Encode(BlobWriter bw, bool oneByteCode)
+ {
+ int len1 = oneByteCode
+ ? EncodeOneByte(val, bw)
+ : Encode7EUnsigned(val, bw);
+ int len2 = (cx.GetMaxBitLength(off) + 6) / 7;
+ bw.Append(String.Format("T0_INT{0}({1})",
+ len2, cx.ToCExpr(off)));
+ return len1 + len2;
+ }
+}
diff --git a/T0/CodeElementUIntInt.cs b/T0/CodeElementUIntInt.cs
new file mode 100644
index 000000000000..0223e27719af
--- /dev/null
+++ b/T0/CodeElementUIntInt.cs
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+
+class CodeElementUIntInt : CodeElement {
+
+ uint val1;
+ int val2;
+
+ internal CodeElementUIntInt(uint val1, int val2) : base()
+ {
+ this.val1 = val1;
+ this.val2 = val2;
+ }
+
+ /* obsolete
+ internal override int Length {
+ get {
+ return Encode7EUnsigned(val1, null)
+ + Encode7ESigned(val2, null);
+ }
+ }
+ */
+
+ internal override int GetLength(bool oneByteCode)
+ {
+ return (oneByteCode ? 1 : Encode7EUnsigned(val1, null))
+ + Encode7ESigned(val2, null);
+ }
+
+ internal override int Encode(BlobWriter bw, bool oneByteCode)
+ {
+ int len = oneByteCode
+ ? EncodeOneByte(val1, bw)
+ : Encode7EUnsigned(val1, bw);
+ len += Encode7ESigned(val2, bw);
+ return len;
+ }
+}
diff --git a/T0/CodeElementUIntUInt.cs b/T0/CodeElementUIntUInt.cs
new file mode 100644
index 000000000000..6f94de54f9d2
--- /dev/null
+++ b/T0/CodeElementUIntUInt.cs
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+
+class CodeElementUIntUInt : CodeElement {
+
+ uint val1, val2;
+
+ internal CodeElementUIntUInt(uint val1, uint val2) : base()
+ {
+ this.val1 = val1;
+ this.val2 = val2;
+ }
+
+ /* obsolete
+ internal override int Length {
+ get {
+ return Encode7EUnsigned(val1, null)
+ + Encode7EUnsigned(val2, null);
+ }
+ }
+ */
+
+ internal override int GetLength(bool oneByteCode)
+ {
+ return (oneByteCode ? 1 : Encode7EUnsigned(val1, null))
+ + Encode7EUnsigned(val2, null);
+ }
+
+ internal override int Encode(BlobWriter bw, bool oneByteCode)
+ {
+ int len = oneByteCode
+ ? EncodeOneByte(val1, bw)
+ : Encode7EUnsigned(val1, bw);
+ len += Encode7EUnsigned(val2, bw);
+ return len;
+ }
+}
diff --git a/T0/ConstData.cs b/T0/ConstData.cs
new file mode 100644
index 000000000000..6a06b64ed145
--- /dev/null
+++ b/T0/ConstData.cs
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+class ConstData {
+
+ internal long ID { get; private set; }
+ internal int Address { get; set; }
+ internal int Length {
+ get {
+ return len;
+ }
+ }
+
+ byte[] buf;
+ int len;
+
+ internal ConstData(T0Comp ctx)
+ {
+ ID = ctx.NextBlobID();
+ buf = new byte[4];
+ len = 0;
+ }
+
+ void Expand(int elen)
+ {
+ int tlen = len + elen;
+ if (tlen > buf.Length) {
+ int nlen = Math.Max(buf.Length << 1, tlen);
+ byte[] nbuf = new byte[nlen];
+ Array.Copy(buf, 0, nbuf, 0, len);
+ buf = nbuf;
+ }
+ }
+
+ internal void Add8(byte b)
+ {
+ Expand(1);
+ buf[len ++] = b;
+ }
+
+ internal void Add16(int x)
+ {
+ Expand(2);
+ buf[len ++] = (byte)(x >> 8);
+ buf[len ++] = (byte)x;
+ }
+
+ internal void Add24(int x)
+ {
+ Expand(3);
+ buf[len ++] = (byte)(x >> 16);
+ buf[len ++] = (byte)(x >> 8);
+ buf[len ++] = (byte)x;
+ }
+
+ internal void Add32(int x)
+ {
+ Expand(4);
+ buf[len ++] = (byte)(x >> 24);
+ buf[len ++] = (byte)(x >> 16);
+ buf[len ++] = (byte)(x >> 8);
+ buf[len ++] = (byte)x;
+ }
+
+ internal void AddString(string s)
+ {
+ byte[] sd = Encoding.UTF8.GetBytes(s);
+ Expand(sd.Length + 1);
+ Array.Copy(sd, 0, buf, len, sd.Length);
+ buf[len + sd.Length] = 0;
+ len += sd.Length + 1;
+ }
+
+ void CheckIndex(int off, int dlen)
+ {
+ if (off < 0 || off > (len - dlen)) {
+ throw new IndexOutOfRangeException();
+ }
+ }
+
+ internal void Set8(int off, byte v)
+ {
+ CheckIndex(off, 1);
+ buf[off] = v;
+ }
+
+ internal byte Read8(int off)
+ {
+ CheckIndex(off, 1);
+ return buf[off];
+ }
+
+ internal int Read16(int off)
+ {
+ CheckIndex(off, 2);
+ return (buf[off] << 8) | buf[off + 1];
+ }
+
+ internal int Read24(int off)
+ {
+ CheckIndex(off, 3);
+ return (buf[off] << 16) | (buf[off + 1] << 8) | buf[off + 2];
+ }
+
+ internal int Read32(int off)
+ {
+ CheckIndex(off, 4);
+ return (buf[off] << 24) | (buf[off + 1] << 16)
+ | (buf[off + 2] << 8) | buf[off + 3];
+ }
+
+ internal string ToString(int off)
+ {
+ StringBuilder sb = new StringBuilder();
+ for (;;) {
+ int x = DecodeUTF8(ref off);
+ if (x == 0) {
+ return sb.ToString();
+ }
+ if (x < 0x10000) {
+ sb.Append((char)x);
+ } else {
+ x -= 0x10000;
+ sb.Append((char)(0xD800 + (x >> 10)));
+ sb.Append((char)(0xDC00 + (x & 0x3FF)));
+ }
+ }
+ }
+
+ int DecodeUTF8(ref int off)
+ {
+ if (off >= len) {
+ throw new IndexOutOfRangeException();
+ }
+ int x = buf[off ++];
+ if (x < 0xC0 || x > 0xF7) {
+ return x;
+ }
+ int elen, acc;
+ if (x >= 0xF0) {
+ elen = 3;
+ acc = x & 0x07;
+ } else if (x >= 0xE0) {
+ elen = 2;
+ acc = x & 0x0F;
+ } else {
+ elen = 1;
+ acc = x & 0x1F;
+ }
+ if (off + elen > len) {
+ return x;
+ }
+ for (int i = 0; i < elen; i ++) {
+ int y = buf[off + i];
+ if (y < 0x80 || y >= 0xC0) {
+ return x;
+ }
+ acc = (acc << 6) + (y & 0x3F);
+ }
+ if (acc > 0x10FFFF) {
+ return x;
+ }
+ off += elen;
+ return acc;
+ }
+
+ internal void Encode(BlobWriter bw)
+ {
+ for (int i = 0; i < len; i ++) {
+ bw.Append(buf[i]);
+ }
+ }
+}
diff --git a/T0/Opcode.cs b/T0/Opcode.cs
new file mode 100644
index 000000000000..81d1e9d7d3d8
--- /dev/null
+++ b/T0/Opcode.cs
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+abstract class Opcode {
+
+ internal Opcode()
+ {
+ }
+
+ /*
+ * Execute this opcode.
+ */
+ internal abstract void Run(CPU cpu);
+
+ /*
+ * Resolve the target (word reference) for this opcode.
+ */
+ internal virtual void ResolveTarget(Word target)
+ {
+ throw new Exception("Not a call opcode");
+ }
+
+ /*
+ * Resolve the jump offset for this opcode. Displacement is
+ * relative to the address of the opcode that immediately follows
+ * the jump code; thus, 0 implies no jump at all.
+ */
+ internal virtual void ResolveJump(int disp)
+ {
+ throw new Exception("Not a jump opcode");
+ }
+
+ /*
+ * Get the Word that this opcode references; this can happen
+ * only with "call" and "const" opcodes. For all other opcodes,
+ * this method returns null.
+ */
+ internal virtual Word GetReference(T0Comp ctx)
+ {
+ return null;
+ }
+
+ /*
+ * Get the data block that this opcode references; this can happen
+ * only with "const" opcodes. For all other opcodes, this method
+ * returns null.
+ */
+ internal virtual ConstData GetDataBlock(T0Comp ctx)
+ {
+ return null;
+ }
+
+ /*
+ * Test whether this opcode may "fall through", i.e. execution
+ * may at least potentially proceed to the next opcode.
+ */
+ internal virtual bool MayFallThrough {
+ get {
+ return true;
+ }
+ }
+
+ /*
+ * Get jump displacement. For non-jump opcodes, this returns 0.
+ */
+ internal virtual int JumpDisp {
+ get {
+ return 0;
+ }
+ }
+
+ /*
+ * Get stack effect for this opcode (number of elements added to
+ * the stack, could be negative). For OpcodeCall, this returns
+ * 0.
+ */
+ internal virtual int StackAction {
+ get {
+ return 0;
+ }
+ }
+
+ internal abstract CodeElement ToCodeElement();
+
+ /*
+ * This method is called for the CodeElement corresponding to
+ * this opcode, at gcode[off]; it is used to compute actual
+ * byte jump offsets when converting code to C.
+ */
+ internal virtual void FixUp(CodeElement[] gcode, int off)
+ {
+ }
+}
diff --git a/T0/OpcodeCall.cs b/T0/OpcodeCall.cs
new file mode 100644
index 000000000000..098004225dce
--- /dev/null
+++ b/T0/OpcodeCall.cs
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class OpcodeCall : Opcode {
+
+ Word target;
+
+ internal OpcodeCall() : this(null)
+ {
+ }
+
+ internal OpcodeCall(Word target)
+ {
+ this.target = target;
+ }
+
+ internal override void ResolveTarget(Word target)
+ {
+ if (this.target != null) {
+ throw new Exception("Opcode already resolved");
+ }
+ this.target = target;
+ }
+
+ internal override void Run(CPU cpu)
+ {
+ target.Run(cpu);
+ }
+
+ internal override Word GetReference(T0Comp ctx)
+ {
+ if (target == null) {
+ throw new Exception("Unresolved call target");
+ }
+ return target;
+ }
+
+ internal override CodeElement ToCodeElement()
+ {
+ return new CodeElementUInt((uint)target.Slot);
+ }
+
+ public override string ToString()
+ {
+ return "call " + (target == null ? "UNRESOLVED" : target.Name);
+ }
+}
diff --git a/T0/OpcodeConst.cs b/T0/OpcodeConst.cs
new file mode 100644
index 000000000000..ae75ae59d651
--- /dev/null
+++ b/T0/OpcodeConst.cs
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class OpcodeConst : Opcode {
+
+ TValue val;
+
+ internal OpcodeConst(TValue val)
+ {
+ this.val = val;
+ }
+
+ internal override void Run(CPU cpu)
+ {
+ cpu.Push(val);
+ }
+
+ internal override Word GetReference(T0Comp ctx)
+ {
+ TPointerXT xt = val.ptr as TPointerXT;
+ if (xt == null) {
+ return null;
+ }
+ xt.Resolve(ctx);
+ return xt.Target;
+ }
+
+ internal override ConstData GetDataBlock(T0Comp ctx)
+ {
+ TPointerBlob bp = val.ptr as TPointerBlob;
+ return bp == null ? null : bp.Blob;
+ }
+
+ internal override CodeElement ToCodeElement()
+ {
+ if (val.ptr == null) {
+ return new CodeElementUIntInt(1, val.Int);
+ }
+ TPointerXT xt = val.ptr as TPointerXT;
+ if (xt != null) {
+ if (val.x != 0) {
+ throw new Exception(
+ "Cannot compile XT: non-zero offset");
+ }
+ return new CodeElementUIntInt(1, xt.Target.Slot);
+ }
+ TPointerBlob bp = val.ptr as TPointerBlob;
+ if (bp != null) {
+ return new CodeElementUIntInt(1,
+ val.x + bp.Blob.Address);
+ }
+ TPointerExpr cx = val.ptr as TPointerExpr;
+ if (cx != null) {
+ return new CodeElementUIntExpr(1, cx, val.x);
+ }
+ throw new Exception(String.Format(
+ "Cannot embed constant (type = {0})",
+ val.ptr.GetType().FullName));
+ }
+
+ internal override int StackAction {
+ get {
+ return 1;
+ }
+ }
+
+ public override string ToString()
+ {
+ return "const " + val.ToString();
+ }
+}
diff --git a/T0/OpcodeGetLocal.cs b/T0/OpcodeGetLocal.cs
new file mode 100644
index 000000000000..59d24fc5c361
--- /dev/null
+++ b/T0/OpcodeGetLocal.cs
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class OpcodeGetLocal : Opcode {
+
+ int num;
+
+ internal OpcodeGetLocal(int num)
+ {
+ this.num = num;
+ }
+
+ internal override void Run(CPU cpu)
+ {
+ cpu.Push(cpu.GetLocal(num));
+ }
+
+ internal override CodeElement ToCodeElement()
+ {
+ return new CodeElementUIntUInt(2, (uint)num);
+ }
+
+ internal override int StackAction {
+ get {
+ return 1;
+ }
+ }
+
+ public override string ToString()
+ {
+ return "getlocal " + num;
+ }
+}
diff --git a/T0/OpcodeJump.cs b/T0/OpcodeJump.cs
new file mode 100644
index 000000000000..4f3ec684d881
--- /dev/null
+++ b/T0/OpcodeJump.cs
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+abstract class OpcodeJump : Opcode {
+
+ int disp;
+
+ internal OpcodeJump() : this(Int32.MinValue)
+ {
+ }
+
+ internal OpcodeJump(int disp)
+ {
+ this.disp = disp;
+ }
+
+ internal override int JumpDisp {
+ get {
+ return disp;
+ }
+ }
+
+ internal override void Run(CPU cpu)
+ {
+ cpu.ipOff += disp;
+ }
+
+ internal override void ResolveJump(int disp)
+ {
+ if (this.disp != Int32.MinValue) {
+ throw new Exception("Jump already resolved");
+ }
+ this.disp = disp;
+ }
+
+ internal override void FixUp(CodeElement[] gcode, int off)
+ {
+ gcode[off].SetJumpTarget(gcode[off + 1 + disp]);
+ }
+}
diff --git a/T0/OpcodeJumpIf.cs b/T0/OpcodeJumpIf.cs
new file mode 100644
index 000000000000..d70243449202
--- /dev/null
+++ b/T0/OpcodeJumpIf.cs
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class OpcodeJumpIf : OpcodeJump {
+
+ internal OpcodeJumpIf() : base()
+ {
+ }
+
+ internal OpcodeJumpIf(int disp) : base(disp)
+ {
+ }
+
+ internal override void Run(CPU cpu)
+ {
+ TValue v = cpu.Pop();
+ if (v.Bool) {
+ base.Run(cpu);
+ }
+ }
+
+ internal override int StackAction {
+ get {
+ return -1;
+ }
+ }
+
+ internal override CodeElement ToCodeElement()
+ {
+ return new CodeElementJump(5);
+ }
+
+ public override string ToString()
+ {
+ if (JumpDisp == Int32.MinValue) {
+ return "jumpif UNRESOLVED";
+ } else {
+ return "jumpif disp=" + JumpDisp;
+ }
+ }
+}
diff --git a/T0/OpcodeJumpIfNot.cs b/T0/OpcodeJumpIfNot.cs
new file mode 100644
index 000000000000..afbf19de5eb5
--- /dev/null
+++ b/T0/OpcodeJumpIfNot.cs
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class OpcodeJumpIfNot : OpcodeJump {
+
+ internal OpcodeJumpIfNot() : base()
+ {
+ }
+
+ internal OpcodeJumpIfNot(int disp) : base(disp)
+ {
+ }
+
+ internal override void Run(CPU cpu)
+ {
+ TValue v = cpu.Pop();
+ if (!v.Bool) {
+ base.Run(cpu);
+ }
+ }
+
+ internal override int StackAction {
+ get {
+ return -1;
+ }
+ }
+
+ internal override CodeElement ToCodeElement()
+ {
+ return new CodeElementJump(6);
+ }
+
+ public override string ToString()
+ {
+ if (JumpDisp == Int32.MinValue) {
+ return "jumpifnot UNRESOLVED";
+ } else {
+ return "jumpifnot disp=" + JumpDisp;
+ }
+ }
+}
diff --git a/T0/OpcodeJumpUncond.cs b/T0/OpcodeJumpUncond.cs
new file mode 100644
index 000000000000..e7d8a82bda3d
--- /dev/null
+++ b/T0/OpcodeJumpUncond.cs
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class OpcodeJumpUncond : OpcodeJump {
+
+ internal OpcodeJumpUncond() : base()
+ {
+ }
+
+ internal OpcodeJumpUncond(int disp) : base(disp)
+ {
+ }
+
+ /*
+ * Unconditional jumps do not "fall through" unless they
+ * happen to be a jump to the next instruction...
+ */
+ internal override bool MayFallThrough {
+ get {
+ return JumpDisp == 0;
+ }
+ }
+
+ internal override CodeElement ToCodeElement()
+ {
+ return new CodeElementJump(4);
+ }
+
+ public override string ToString()
+ {
+ if (JumpDisp == Int32.MinValue) {
+ return "jump UNRESOLVED";
+ } else {
+ return "jump disp=" + JumpDisp;
+ }
+ }
+}
diff --git a/T0/OpcodePutLocal.cs b/T0/OpcodePutLocal.cs
new file mode 100644
index 000000000000..b148a65b9ca2
--- /dev/null
+++ b/T0/OpcodePutLocal.cs
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class OpcodePutLocal : Opcode {
+
+ int num;
+
+ internal OpcodePutLocal(int num)
+ {
+ this.num = num;
+ }
+
+ internal override void Run(CPU cpu)
+ {
+ cpu.PutLocal(num, cpu.Pop());
+ }
+
+ internal override CodeElement ToCodeElement()
+ {
+ return new CodeElementUIntUInt(3, (uint)num);
+ }
+
+ internal override int StackAction {
+ get {
+ return -1;
+ }
+ }
+
+ public override string ToString()
+ {
+ return "putlocal " + num;
+ }
+}
diff --git a/T0/OpcodeRet.cs b/T0/OpcodeRet.cs
new file mode 100644
index 000000000000..187473b1d60e
--- /dev/null
+++ b/T0/OpcodeRet.cs
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class OpcodeRet : Opcode {
+
+ internal override void Run(CPU cpu)
+ {
+ cpu.Exit();
+ }
+
+ internal override bool MayFallThrough {
+ get {
+ return false;
+ }
+ }
+
+ internal override CodeElement ToCodeElement()
+ {
+ return new CodeElementUInt(0);
+ }
+
+ public override string ToString()
+ {
+ return "ret";
+ }
+}
diff --git a/T0/SType.cs b/T0/SType.cs
new file mode 100644
index 000000000000..80e9f0176e18
--- /dev/null
+++ b/T0/SType.cs
@@ -0,0 +1,129 @@
+using System;
+
+/*
+ * This structure contains the stack effect of a word: number of stack
+ * element consumed on input, and number of stack element produced on
+ * output.
+ */
+
+struct SType {
+
+ /*
+ * Get number of stack elements consumed on input; this is -1 if
+ * the stack effect is not known.
+ */
+ internal int DataIn {
+ get {
+ return din;
+ }
+ }
+
+ /*
+ * Get number of stack elements produced on output; this is -1 if
+ * either the stack effect is not known, or if the word never
+ * exits.
+ */
+ internal int DataOut {
+ get {
+ return dout;
+ }
+ }
+
+ /*
+ * Tell whether the stack effect is known.
+ */
+ internal bool IsKnown {
+ get {
+ return din >= 0;
+ }
+ }
+
+ /*
+ * Tell whether the stack effect is known and the word never exits.
+ */
+ internal bool NoExit {
+ get {
+ return din >= 0 && dout < 0;
+ }
+ }
+
+ int din, dout;
+
+ internal SType(int din, int dout)
+ {
+ if (din < 0) {
+ din = -1;
+ }
+ if (dout < 0) {
+ dout = -1;
+ }
+ this.din = din;
+ this.dout = dout;
+ }
+
+ /*
+ * Special value for the unknown stack effect.
+ */
+ internal static SType UNKNOWN = new SType(-1, -1);
+
+ /*
+ * Constant for the "blank stack effect".
+ */
+ internal static SType BLANK = new SType(0, 0);
+
+ public static bool operator ==(SType s1, SType s2)
+ {
+ return s1.din == s2.din && s1.dout == s2.dout;
+ }
+
+ public static bool operator !=(SType s1, SType s2)
+ {
+ return s1.din != s2.din || s1.dout != s2.dout;
+ }
+
+ public override bool Equals(Object obj)
+ {
+ return (obj is SType) && ((SType)obj == this);
+ }
+
+ public override int GetHashCode()
+ {
+ return din * 31 + dout * 17;
+ }
+
+ public override string ToString()
+ {
+ if (!IsKnown) {
+ return "UNKNOWN";
+ } else if (NoExit) {
+ return string.Format("in:{0},noexit", din);
+ } else {
+ return string.Format("in:{0},out:{1}", din, dout);
+ }
+ }
+
+ /*
+ * Test whether this stack effect is a sub-effect of the provided
+ * stack effect s. Stack effect s1 is a sub-effect of stack-effect
+ * s2 if any of the following holds:
+ * -- s1 and s2 are known, s1.din <= s2.din and s1 does not exit.
+ * -- s1 and s2 are known, s1.din <= s2.din, s1 and s2 exit,
+ * and s1.din - s1.dout == s2.din - s2.dout.
+ */
+ internal bool IsSubOf(SType s)
+ {
+ if (!IsKnown || !s.IsKnown) {
+ return false;
+ }
+ if (din > s.din) {
+ return false;
+ }
+ if (NoExit) {
+ return true;
+ }
+ if (s.NoExit) {
+ return false;
+ }
+ return (din - dout) == (s.din - s.dout);
+ }
+}
diff --git a/T0/T0Comp.cs b/T0/T0Comp.cs
new file mode 100644
index 000000000000..7a397f7cbc48
--- /dev/null
+++ b/T0/T0Comp.cs
@@ -0,0 +1,2123 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+
+/*
+ * This is the main compiler class.
+ */
+
+public class T0Comp {
+
+ /*
+ * Command-line entry point.
+ */
+ public static void Main(string[] args)
+ {
+ try {
+ List<string> r = new List<string>();
+ string outBase = null;
+ List<string> entryPoints = new List<string>();
+ string coreRun = null;
+ bool flow = true;
+ int dsLim = 32;
+ int rsLim = 32;
+ for (int i = 0; i < args.Length; i ++) {
+ string a = args[i];
+ if (!a.StartsWith("-")) {
+ r.Add(a);
+ continue;
+ }
+ if (a == "--") {
+ for (;;) {
+ if (++ i >= args.Length) {
+ break;
+ }
+ r.Add(args[i]);
+ }
+ break;
+ }
+ while (a.StartsWith("-")) {
+ a = a.Substring(1);
+ }
+ int j = a.IndexOf('=');
+ string pname;
+ string pval, pval2;
+ if (j < 0) {
+ pname = a.ToLowerInvariant();
+ pval = null;
+ pval2 = (i + 1) < args.Length
+ ? args[i + 1] : null;
+ } else {
+ pname = a.Substring(0, j).Trim()
+ .ToLowerInvariant();
+ pval = a.Substring(j + 1);
+ pval2 = null;
+ }
+ switch (pname) {
+ case "o":
+ case "out":
+ if (pval == null) {
+ if (pval2 == null) {
+ Usage();
+ }
+ i ++;
+ pval = pval2;
+ }
+ if (outBase != null) {
+ Usage();
+ }
+ outBase = pval;
+ break;
+ case "r":
+ case "run":
+ if (pval == null) {
+ if (pval2 == null) {
+ Usage();
+ }
+ i ++;
+ pval = pval2;
+ }
+ coreRun = pval;
+ break;
+ case "m":
+ case "main":
+ if (pval == null) {
+ if (pval2 == null) {
+ Usage();
+ }
+ i ++;
+ pval = pval2;
+ }
+ foreach (string ep in pval.Split(',')) {
+ string epz = ep.Trim();
+ if (epz.Length > 0) {
+ entryPoints.Add(epz);
+ }
+ }
+ break;
+ case "nf":
+ case "noflow":
+ flow = false;
+ break;
+ default:
+ Usage();
+ break;
+ }
+ }
+ if (r.Count == 0) {
+ Usage();
+ }
+ if (outBase == null) {
+ outBase = "t0out";
+ }
+ if (entryPoints.Count == 0) {
+ entryPoints.Add("main");
+ }
+ if (coreRun == null) {
+ coreRun = outBase;
+ }
+ T0Comp tc = new T0Comp();
+ tc.enableFlowAnalysis = flow;
+ tc.dsLimit = dsLim;
+ tc.rsLimit = rsLim;
+ using (TextReader tr = new StreamReader(
+ Assembly.GetExecutingAssembly()
+ .GetManifestResourceStream("t0-kernel")))
+ {
+ tc.ProcessInput(tr);
+ }
+ foreach (string a in r) {
+ Console.WriteLine("[{0}]", a);
+ using (TextReader tr = File.OpenText(a)) {
+ tc.ProcessInput(tr);
+ }
+ }
+ tc.Generate(outBase, coreRun, entryPoints.ToArray());
+ } catch (Exception e) {
+ Console.WriteLine(e.ToString());
+ Environment.Exit(1);
+ }
+ }
+
+ static void Usage()
+ {
+ Console.WriteLine(
+"usage: T0Comp.exe [ options... ] file...");
+ Console.WriteLine(
+"options:");
+ Console.WriteLine(
+" -o file use 'file' as base for output file name (default: 't0out')");
+ Console.WriteLine(
+" -r name use 'name' as base for run function (default: same as output)");
+ Console.WriteLine(
+" -m name[,name...]");
+ Console.WriteLine(
+" define entry point(s)");
+ Console.WriteLine(
+" -nf disable flow analysis");
+ Environment.Exit(1);
+ }
+
+ /*
+ * If 'delayedChar' is Int32.MinValue then there is no delayed
+ * character.
+ * If 'delayedChar' equals x >= 0 then there is one delayed
+ * character of value x.
+ * If 'delayedChar' equals y < 0 then there are two delayed
+ * characters, a newline (U+000A) followed by character of
+ * value -(y+1).
+ */
+ TextReader currentInput;
+ int delayedChar;
+
+ /*
+ * Common StringBuilder used to parse tokens; it is reused for
+ * each new token.
+ */
+ StringBuilder tokenBuilder;
+
+ /*
+ * There may be a delayed token in some cases.
+ */
+ String delayedToken;
+
+ /*
+ * Defined words are referenced by name in this map. Names are
+ * string-sensitive; for better reproducibility, the map is sorted
+ * (ordinal order).
+ */
+ IDictionary<string, Word> words;
+
+ /*
+ * Last defined word is also referenced in 'lastWord'. This is
+ * used by 'immediate'.
+ */
+ Word lastWord;
+
+ /*
+ * When compiling, this builder is used. A stack saves other
+ * builders in case of nested definition.
+ */
+ WordBuilder wordBuilder;
+ Stack<WordBuilder> savedWordBuilders;
+
+ /*
+ * C code defined for words is kept in this map, by word name.
+ */
+ IDictionary<string, string> allCCode;
+
+ /*
+ * 'compiling' is true when compiling tokens to a word, false
+ * when interpreting them.
+ */
+ bool compiling;
+
+ /*
+ * 'quitRunLoop' is set to true to trigger exit of the
+ * interpretation loop when the end of the current input file
+ * is reached.
+ */
+ bool quitRunLoop;
+
+ /*
+ * 'extraCode' is for C code that is to be added as preamble to
+ * the C output.
+ */
+ List<string> extraCode;
+
+ /*
+ * 'extraCodeDefer' is for C code that is to be added in the C
+ * output _after_ the data and code blocks.
+ */
+ List<string> extraCodeDefer;
+
+ /*
+ * 'dataBlock' is the data block in which constant data bytes
+ * are accumulated.
+ */
+ ConstData dataBlock;
+
+ /*
+ * Counter for blocks of constant data.
+ */
+ long currentBlobID;
+
+ /*
+ * Flow analysis enable flag.
+ */
+ bool enableFlowAnalysis;
+
+ /*
+ * Data stack size limit.
+ */
+ int dsLimit;
+
+ /*
+ * Return stack size limit.
+ */
+ int rsLimit;
+
+ T0Comp()
+ {
+ tokenBuilder = new StringBuilder();
+ words = new SortedDictionary<string, Word>(
+ StringComparer.Ordinal);
+ savedWordBuilders = new Stack<WordBuilder>();
+ allCCode = new SortedDictionary<string, string>(
+ StringComparer.Ordinal);
+ compiling = false;
+ extraCode = new List<string>();
+ extraCodeDefer = new List<string>();
+ enableFlowAnalysis = true;
+
+ /*
+ * Native words are predefined and implemented only with
+ * native code. Some may be part of the generated output,
+ * if C code is set for them.
+ */
+
+ /*
+ * add-cc:
+ * Parses next token as a word name, then a C code snippet.
+ * Sets the C code for that word.
+ */
+ AddNative("add-cc:", false, SType.BLANK, cpu => {
+ string tt = Next();
+ if (tt == null) {
+ throw new Exception(
+ "EOF reached (missing name)");
+ }
+ if (allCCode.ContainsKey(tt)) {
+ throw new Exception(
+ "C code already set for: " + tt);
+ }
+ allCCode[tt] = ParseCCode();
+ });
+
+ /*
+ * cc:
+ * Parses next token as a word name, then a C code snippet.
+ * A new word is defined, that throws an exception when
+ * invoked during compilation. The C code is set for that
+ * new word.
+ */
+ AddNative("cc:", false, SType.BLANK, cpu => {
+ string tt = Next();
+ if (tt == null) {
+ throw new Exception(
+ "EOF reached (missing name)");
+ }
+ Word w = AddNative(tt, false, cpu2 => {
+ throw new Exception(
+ "C-only word: " + tt);
+ });
+ if (allCCode.ContainsKey(tt)) {
+ throw new Exception(
+ "C code already set for: " + tt);
+ }
+ SType stackEffect;
+ allCCode[tt] = ParseCCode(out stackEffect);
+ w.StackEffect = stackEffect;
+ });
+
+ /*
+ * preamble
+ * Parses a C code snippet, then adds it to the generated
+ * output preamble.
+ */
+ AddNative("preamble", false, SType.BLANK, cpu => {
+ extraCode.Add(ParseCCode());
+ });
+
+ /*
+ * postamble
+ * Parses a C code snippet, then adds it to the generated
+ * output after the data and code blocks.
+ */
+ AddNative("postamble", false, SType.BLANK, cpu => {
+ extraCodeDefer.Add(ParseCCode());
+ });
+
+ /*
+ * make-CX
+ * Expects two integers and a string, and makes a
+ * constant that stands for the string as a C constant
+ * expression. The two integers are the expected range
+ * (min-max, inclusive).
+ */
+ AddNative("make-CX", false, new SType(3, 1), cpu => {
+ TValue c = cpu.Pop();
+ if (!(c.ptr is TPointerBlob)) {
+ throw new Exception(string.Format(
+ "'{0}' is not a string", c));
+ }
+ int max = cpu.Pop();
+ int min = cpu.Pop();
+ TValue tv = new TValue(0, new TPointerExpr(
+ c.ToString(), min, max));
+ cpu.Push(tv);
+ });
+
+ /*
+ * CX (immediate)
+ * Parses two integer constants, then a C code snippet.
+ * It then pushes on the stack, or compiles to the
+ * current word, a value consisting of the given C
+ * expression; the two integers indicate the expected
+ * range (min-max, inclusive) of the C expression when
+ * evaluated.
+ */
+ AddNative("CX", true, cpu => {
+ string tt = Next();
+ if (tt == null) {
+ throw new Exception(
+ "EOF reached (missing min value)");
+ }
+ int min = ParseInteger(tt);
+ tt = Next();
+ if (tt == null) {
+ throw new Exception(
+ "EOF reached (missing max value)");
+ }
+ int max = ParseInteger(tt);
+ if (max < min) {
+ throw new Exception("min/max in wrong order");
+ }
+ TValue tv = new TValue(0, new TPointerExpr(
+ ParseCCode().Trim(), min, max));
+ if (compiling) {
+ wordBuilder.Literal(tv);
+ } else {
+ cpu.Push(tv);
+ }
+ });
+
+ /*
+ * co
+ * Interrupt the current execution. This implements
+ * coroutines. It cannot be invoked during compilation.
+ */
+ AddNative("co", false, SType.BLANK, cpu => {
+ throw new Exception("No coroutine in compile mode");
+ });
+
+ /*
+ * :
+ * Parses next token as word name. It begins definition
+ * of that word, setting it as current target for
+ * word building. Any previously opened word is saved
+ * and will become available again as a target when that
+ * new word is finished building.
+ */
+ AddNative(":", false, cpu => {
+ string tt = Next();
+ if (tt == null) {
+ throw new Exception(
+ "EOF reached (missing name)");
+ }
+ if (compiling) {
+ savedWordBuilders.Push(wordBuilder);
+ } else {
+ compiling = true;
+ }
+ wordBuilder = new WordBuilder(this, tt);
+ tt = Next();
+ if (tt == null) {
+ throw new Exception(
+ "EOF reached (while compiling)");
+ }
+ if (tt == "(") {
+ SType stackEffect = ParseStackEffectNF();
+ if (!stackEffect.IsKnown) {
+ throw new Exception(
+ "Invalid stack effect syntax");
+ }
+ wordBuilder.StackEffect = stackEffect;
+ } else {
+ delayedToken = tt;
+ }
+ });
+
+ /*
+ * Pops a string as word name, and two integers as stack
+ * effect. It begins definition of that word, setting it
+ * as current target for word building. Any previously
+ * opened word is saved and will become available again as
+ * a target when that new word is finished building.
+ *
+ * Stack effect is the pair 'din dout'. If din is negative,
+ * then the stack effect is "unknown". If din is nonnegative
+ * but dout is negative, then the word is reputed never to
+ * return.
+ */
+ AddNative("define-word", false, cpu => {
+ int dout = cpu.Pop();
+ int din = cpu.Pop();
+ TValue s = cpu.Pop();
+ if (!(s.ptr is TPointerBlob)) {
+ throw new Exception(string.Format(
+ "Not a string: '{0}'", s));
+ }
+ string tt = s.ToString();
+ if (compiling) {
+ savedWordBuilders.Push(wordBuilder);
+ } else {
+ compiling = true;
+ }
+ wordBuilder = new WordBuilder(this, tt);
+ wordBuilder.StackEffect = new SType(din, dout);
+ });
+
+ /*
+ * ; (immediate)
+ * Ends current word. The current word is registered under
+ * its name, and the previously opened word (if any) becomes
+ * again the building target.
+ */
+ AddNative(";", true, cpu => {
+ if (!compiling) {
+ throw new Exception("Not compiling");
+ }
+ Word w = wordBuilder.Build();
+ string name = w.Name;
+ if (words.ContainsKey(name)) {
+ throw new Exception(
+ "Word already defined: " + name);
+ }
+ words[name] = w;
+ lastWord = w;
+ if (savedWordBuilders.Count > 0) {
+ wordBuilder = savedWordBuilders.Pop();
+ } else {
+ wordBuilder = null;
+ compiling = false;
+ }
+ });
+
+ /*
+ * immediate
+ * Sets the last defined word as immediate.
+ */
+ AddNative("immediate", false, cpu => {
+ if (lastWord == null) {
+ throw new Exception("No word defined yet");
+ }
+ lastWord.Immediate = true;
+ });
+
+ /*
+ * literal (immediate)
+ * Pops the current TOS value, and add in the current word
+ * the action of pushing that value. This cannot be used
+ * when no word is being built.
+ */
+ WordNative wliteral = AddNative("literal", true, cpu => {
+ CheckCompiling();
+ wordBuilder.Literal(cpu.Pop());
+ });
+
+ /*
+ * compile
+ * Pops the current TOS value, which must be an XT (pointer
+ * to a word); the action of calling that word is compiled
+ * in the current word.
+ */
+ WordNative wcompile = AddNative("compile", false, cpu => {
+ CheckCompiling();
+ wordBuilder.Call(cpu.Pop().ToXT());
+ });
+
+ /*
+ * postpone (immediate)
+ * Parses the next token as a word name, and add to the
+ * current word the action of calling that word. This
+ * basically removes immediatety from the next word.
+ */
+ AddNative("postpone", true, cpu => {
+ CheckCompiling();
+ string tt = Next();
+ if (tt == null) {
+ throw new Exception(
+ "EOF reached (missing name)");
+ }
+ TValue v;
+ bool isVal = TryParseLiteral(tt, out v);
+ Word w = LookupNF(tt);
+ if (isVal && w != null) {
+ throw new Exception(String.Format(
+ "Ambiguous: both defined word and"
+ + " literal: {0}", tt));
+ }
+ if (isVal) {
+ wordBuilder.Literal(v);
+ wordBuilder.CallExt(wliteral);
+ } else if (w != null) {
+ if (w.Immediate) {
+ wordBuilder.CallExt(w);
+ } else {
+ wordBuilder.Literal(new TValue(0,
+ new TPointerXT(w)));
+ wordBuilder.CallExt(wcompile);
+ }
+ } else {
+ wordBuilder.Literal(new TValue(0,
+ new TPointerXT(tt)));
+ wordBuilder.CallExt(wcompile);
+ }
+ });
+
+ /*
+ * Interrupt compilation with an error.
+ */
+ AddNative("exitvm", false, cpu => {
+ throw new Exception();
+ });
+
+ /*
+ * Open a new data block. Its symbolic address is pushed
+ * on the stack.
+ */
+ AddNative("new-data-block", false, cpu => {
+ dataBlock = new ConstData(this);
+ cpu.Push(new TValue(0, new TPointerBlob(dataBlock)));
+ });
+
+ /*
+ * Define a new data word. The data address and name are
+ * popped from the stack.
+ */
+ AddNative("define-data-word", false, cpu => {
+ string name = cpu.Pop().ToString();
+ TValue va = cpu.Pop();
+ TPointerBlob tb = va.ptr as TPointerBlob;
+ if (tb == null) {
+ throw new Exception(
+ "Address is not a data area");
+ }
+ Word w = new WordData(this, name, tb.Blob, va.x);
+ if (words.ContainsKey(name)) {
+ throw new Exception(
+ "Word already defined: " + name);
+ }
+ words[name] = w;
+ lastWord = w;
+ });
+
+ /*
+ * Get an address pointing at the end of the current
+ * data block. This is the address of the next byte that
+ * will be added.
+ */
+ AddNative("current-data", false, cpu => {
+ if (dataBlock == null) {
+ throw new Exception(
+ "No current data block");
+ }
+ cpu.Push(new TValue(dataBlock.Length,
+ new TPointerBlob(dataBlock)));
+ });
+
+ /*
+ * Add a byte value to the data block.
+ */
+ AddNative("data-add8", false, cpu => {
+ if (dataBlock == null) {
+ throw new Exception(
+ "No current data block");
+ }
+ int v = cpu.Pop();
+ if (v < 0 || v > 0xFF) {
+ throw new Exception(
+ "Byte value out of range: " + v);
+ }
+ dataBlock.Add8((byte)v);
+ });
+
+ /*
+ * Set a byte value in the data block.
+ */
+ AddNative("data-set8", false, cpu => {
+ TValue va = cpu.Pop();
+ TPointerBlob tb = va.ptr as TPointerBlob;
+ if (tb == null) {
+ throw new Exception(
+ "Address is not a data area");
+ }
+ int v = cpu.Pop();
+ if (v < 0 || v > 0xFF) {
+ throw new Exception(
+ "Byte value out of range: " + v);
+ }
+ tb.Blob.Set8(va.x, (byte)v);
+ });
+
+ /*
+ * Get a byte value from a data block.
+ */
+ AddNative("data-get8", false, new SType(1, 1), cpu => {
+ TValue va = cpu.Pop();
+ TPointerBlob tb = va.ptr as TPointerBlob;
+ if (tb == null) {
+ throw new Exception(
+ "Address is not a data area");
+ }
+ int v = tb.Blob.Read8(va.x);
+ cpu.Push(v);
+ });
+
+ /*
+ *
+ */
+ AddNative("compile-local-read", false, cpu => {
+ CheckCompiling();
+ wordBuilder.GetLocal(cpu.Pop().ToString());
+ });
+ AddNative("compile-local-write", false, cpu => {
+ CheckCompiling();
+ wordBuilder.PutLocal(cpu.Pop().ToString());
+ });
+
+ AddNative("ahead", true, cpu => {
+ CheckCompiling();
+ wordBuilder.Ahead();
+ });
+ AddNative("begin", true, cpu => {
+ CheckCompiling();
+ wordBuilder.Begin();
+ });
+ AddNative("again", true, cpu => {
+ CheckCompiling();
+ wordBuilder.Again();
+ });
+ AddNative("until", true, cpu => {
+ CheckCompiling();
+ wordBuilder.AgainIfNot();
+ });
+ AddNative("untilnot", true, cpu => {
+ CheckCompiling();
+ wordBuilder.AgainIf();
+ });
+ AddNative("if", true, cpu => {
+ CheckCompiling();
+ wordBuilder.AheadIfNot();
+ });
+ AddNative("ifnot", true, cpu => {
+ CheckCompiling();
+ wordBuilder.AheadIf();
+ });
+ AddNative("then", true, cpu => {
+ CheckCompiling();
+ wordBuilder.Then();
+ });
+ AddNative("cs-pick", false, cpu => {
+ CheckCompiling();
+ wordBuilder.CSPick(cpu.Pop());
+ });
+ AddNative("cs-roll", false, cpu => {
+ CheckCompiling();
+ wordBuilder.CSRoll(cpu.Pop());
+ });
+ AddNative("next-word", false, cpu => {
+ string s = Next();
+ if (s == null) {
+ throw new Exception("No next word (EOF)");
+ }
+ cpu.Push(StringToBlob(s));
+ });
+ AddNative("parse", false, cpu => {
+ int d = cpu.Pop();
+ string s = ReadTerm(d);
+ cpu.Push(StringToBlob(s));
+ });
+ AddNative("char", false, cpu => {
+ int c = NextChar();
+ if (c < 0) {
+ throw new Exception("No next character (EOF)");
+ }
+ cpu.Push(c);
+ });
+ AddNative("'", false, cpu => {
+ string name = Next();
+ cpu.Push(new TValue(0, new TPointerXT(name)));
+ });
+
+ /*
+ * The "execute" word is valid in generated C code, but
+ * since it jumps to a runtime pointer, its actual stack
+ * effect cannot be computed in advance.
+ */
+ AddNative("execute", false, cpu => {
+ cpu.Pop().Execute(this, cpu);
+ });
+
+ AddNative("[", true, cpu => {
+ CheckCompiling();
+ compiling = false;
+ });
+ AddNative("]", false, cpu => {
+ compiling = true;
+ });
+ AddNative("(local)", false, cpu => {
+ CheckCompiling();
+ wordBuilder.DefLocal(cpu.Pop().ToString());
+ });
+ AddNative("ret", true, cpu => {
+ CheckCompiling();
+ wordBuilder.Ret();
+ });
+
+ AddNative("drop", false, new SType(1, 0), cpu => {
+ cpu.Pop();
+ });
+ AddNative("dup", false, new SType(1, 2), cpu => {
+ cpu.Push(cpu.Peek(0));
+ });
+ AddNative("swap", false, new SType(2, 2), cpu => {
+ cpu.Rot(1);
+ });
+ AddNative("over", false, new SType(2, 3), cpu => {
+ cpu.Push(cpu.Peek(1));
+ });
+ AddNative("rot", false, new SType(3, 3), cpu => {
+ cpu.Rot(2);
+ });
+ AddNative("-rot", false, new SType(3, 3), cpu => {
+ cpu.NRot(2);
+ });
+
+ /*
+ * "roll" and "pick" are special in that the stack slot
+ * they inspect might be known only at runtime, so an
+ * absolute stack effect cannot be attributed. Instead,
+ * we simply hope that the caller knows what it is doing,
+ * and we use a simple stack effect for just the count
+ * value and picked value.
+ */
+ AddNative("roll", false, new SType(1, 0), cpu => {
+ cpu.Rot(cpu.Pop());
+ });
+ AddNative("pick", false, new SType(1, 1), cpu => {
+ cpu.Push(cpu.Peek(cpu.Pop()));
+ });
+
+ AddNative("+", false, new SType(2, 1), cpu => {
+ TValue b = cpu.Pop();
+ TValue a = cpu.Pop();
+ if (b.ptr == null) {
+ a.x += (int)b;
+ cpu.Push(a);
+ } else if (a.ptr is TPointerBlob
+ && b.ptr is TPointerBlob)
+ {
+ cpu.Push(StringToBlob(
+ a.ToString() + b.ToString()));
+ } else {
+ throw new Exception(string.Format(
+ "Cannot add '{0}' to '{1}'", b, a));
+ }
+ });
+ AddNative("-", false, new SType(2, 1), cpu => {
+ /*
+ * We can subtract two pointers, provided that
+ * they point to the same blob. Otherwise,
+ * the subtraction second operand must be an
+ * integer.
+ */
+ TValue b = cpu.Pop();
+ TValue a = cpu.Pop();
+ TPointerBlob ap = a.ptr as TPointerBlob;
+ TPointerBlob bp = b.ptr as TPointerBlob;
+ if (ap != null && bp != null && ap.Blob == bp.Blob) {
+ cpu.Push(new TValue(a.x - b.x));
+ return;
+ }
+ int bx = b;
+ a.x -= bx;
+ cpu.Push(a);
+ });
+ AddNative("neg", false, new SType(1, 1), cpu => {
+ int ax = cpu.Pop();
+ cpu.Push(-ax);
+ });
+ AddNative("*", false, new SType(2, 1), cpu => {
+ int bx = cpu.Pop();
+ int ax = cpu.Pop();
+ cpu.Push(ax * bx);
+ });
+ AddNative("/", false, new SType(2, 1), cpu => {
+ int bx = cpu.Pop();
+ int ax = cpu.Pop();
+ cpu.Push(ax / bx);
+ });
+ AddNative("u/", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop();
+ uint ax = cpu.Pop();
+ cpu.Push(ax / bx);
+ });
+ AddNative("%", false, new SType(2, 1), cpu => {
+ int bx = cpu.Pop();
+ int ax = cpu.Pop();
+ cpu.Push(ax % bx);
+ });
+ AddNative("u%", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop();
+ uint ax = cpu.Pop();
+ cpu.Push(ax % bx);
+ });
+ AddNative("<", false, new SType(2, 1), cpu => {
+ int bx = cpu.Pop();
+ int ax = cpu.Pop();
+ cpu.Push(ax < bx);
+ });
+ AddNative("<=", false, new SType(2, 1), cpu => {
+ int bx = cpu.Pop();
+ int ax = cpu.Pop();
+ cpu.Push(ax <= bx);
+ });
+ AddNative(">", false, new SType(2, 1), cpu => {
+ int bx = cpu.Pop();
+ int ax = cpu.Pop();
+ cpu.Push(ax > bx);
+ });
+ AddNative(">=", false, new SType(2, 1), cpu => {
+ int bx = cpu.Pop();
+ int ax = cpu.Pop();
+ cpu.Push(ax >= bx);
+ });
+ AddNative("=", false, new SType(2, 1), cpu => {
+ TValue b = cpu.Pop();
+ TValue a = cpu.Pop();
+ cpu.Push(a.Equals(b));
+ });
+ AddNative("<>", false, new SType(2, 1), cpu => {
+ TValue b = cpu.Pop();
+ TValue a = cpu.Pop();
+ cpu.Push(!a.Equals(b));
+ });
+ AddNative("u<", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop().UInt;
+ uint ax = cpu.Pop().UInt;
+ cpu.Push(new TValue(ax < bx));
+ });
+ AddNative("u<=", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop().UInt;
+ uint ax = cpu.Pop().UInt;
+ cpu.Push(new TValue(ax <= bx));
+ });
+ AddNative("u>", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop().UInt;
+ uint ax = cpu.Pop().UInt;
+ cpu.Push(new TValue(ax > bx));
+ });
+ AddNative("u>=", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop();
+ uint ax = cpu.Pop();
+ cpu.Push(ax >= bx);
+ });
+ AddNative("and", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop();
+ uint ax = cpu.Pop();
+ cpu.Push(ax & bx);
+ });
+ AddNative("or", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop();
+ uint ax = cpu.Pop();
+ cpu.Push(ax | bx);
+ });
+ AddNative("xor", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop();
+ uint ax = cpu.Pop();
+ cpu.Push(ax ^ bx);
+ });
+ AddNative("not", false, new SType(1, 1), cpu => {
+ uint ax = cpu.Pop();
+ cpu.Push(~ax);
+ });
+ AddNative("<<", false, new SType(2, 1), cpu => {
+ int count = cpu.Pop();
+ if (count < 0 || count > 31) {
+ throw new Exception("Invalid shift count");
+ }
+ uint ax = cpu.Pop();
+ cpu.Push(ax << count);
+ });
+ AddNative(">>", false, new SType(2, 1), cpu => {
+ int count = cpu.Pop();
+ if (count < 0 || count > 31) {
+ throw new Exception("Invalid shift count");
+ }
+ int ax = cpu.Pop();
+ cpu.Push(ax >> count);
+ });
+ AddNative("u>>", false, new SType(2, 1), cpu => {
+ int count = cpu.Pop();
+ if (count < 0 || count > 31) {
+ throw new Exception("Invalid shift count");
+ }
+ uint ax = cpu.Pop();
+ cpu.Push(ax >> count);
+ });
+
+ AddNative(".", false, new SType(1, 0), cpu => {
+ Console.Write(" {0}", cpu.Pop().ToString());
+ });
+ AddNative(".s", false, SType.BLANK, cpu => {
+ int n = cpu.Depth;
+ for (int i = n - 1; i >= 0; i --) {
+ Console.Write(" {0}", cpu.Peek(i).ToString());
+ }
+ });
+ AddNative("putc", false, new SType(1, 0), cpu => {
+ Console.Write((char)cpu.Pop());
+ });
+ AddNative("puts", false, new SType(1, 0), cpu => {
+ Console.Write("{0}", cpu.Pop().ToString());
+ });
+ AddNative("cr", false, SType.BLANK, cpu => {
+ Console.WriteLine();
+ });
+ AddNative("eqstr", false, new SType(2, 1), cpu => {
+ string s2 = cpu.Pop().ToString();
+ string s1 = cpu.Pop().ToString();
+ cpu.Push(s1 == s2);
+ });
+ }
+
+ WordNative AddNative(string name, bool immediate,
+ WordNative.NativeRun code)
+ {
+ return AddNative(name, immediate, SType.UNKNOWN, code);
+ }
+
+ WordNative AddNative(string name, bool immediate, SType stackEffect,
+ WordNative.NativeRun code)
+ {
+ if (words.ContainsKey(name)) {
+ throw new Exception(
+ "Word already defined: " + name);
+ }
+ WordNative w = new WordNative(this, name, code);
+ w.Immediate = immediate;
+ w.StackEffect = stackEffect;
+ words[name] = w;
+ return w;
+ }
+
+ internal long NextBlobID()
+ {
+ return currentBlobID ++;
+ }
+
+ int NextChar()
+ {
+ int c = delayedChar;
+ if (c >= 0) {
+ delayedChar = Int32.MinValue;
+ } else if (c > Int32.MinValue) {
+ delayedChar = -(c + 1);
+ c = '\n';
+ } else {
+ c = currentInput.Read();
+ }
+ if (c == '\r') {
+ if (delayedChar >= 0) {
+ c = delayedChar;
+ delayedChar = Int32.MinValue;
+ } else {
+ c = currentInput.Read();
+ }
+ if (c != '\n') {
+ delayedChar = c;
+ c = '\n';
+ }
+ }
+ return c;
+ }
+
+ /*
+ * Un-read the character value 'c'. That value MUST be the one
+ * that was obtained from NextChar().
+ */
+ void Unread(int c)
+ {
+ if (c < 0) {
+ return;
+ }
+ if (delayedChar < 0) {
+ if (delayedChar != Int32.MinValue) {
+ throw new Exception(
+ "Already two delayed characters");
+ }
+ delayedChar = c;
+ } else if (c != '\n') {
+ throw new Exception("Cannot delay two characters");
+ } else {
+ delayedChar = -(delayedChar + 1);
+ }
+ }
+
+ string Next()
+ {
+ string r = delayedToken;
+ if (r != null) {
+ delayedToken = null;
+ return r;
+ }
+ tokenBuilder.Length = 0;
+ int c;
+ for (;;) {
+ c = NextChar();
+ if (c < 0) {
+ return null;
+ }
+ if (!IsWS(c)) {
+ break;
+ }
+ }
+ if (c == '"') {
+ return ParseString();
+ }
+ for (;;) {
+ tokenBuilder.Append((char)c);
+ c = NextChar();
+ if (c < 0 || IsWS(c)) {
+ Unread(c);
+ return tokenBuilder.ToString();
+ }
+ }
+ }
+
+ string ParseCCode()
+ {
+ SType stackEffect;
+ string r = ParseCCode(out stackEffect);
+ if (stackEffect.IsKnown) {
+ throw new Exception(
+ "Stack effect forbidden in this declaration");
+ }
+ return r;
+ }
+
+ string ParseCCode(out SType stackEffect)
+ {
+ string s = ParseCCodeNF(out stackEffect);
+ if (s == null) {
+ throw new Exception("Error while parsing C code");
+ }
+ return s;
+ }
+
+ string ParseCCodeNF(out SType stackEffect)
+ {
+ stackEffect = SType.UNKNOWN;
+ for (;;) {
+ int c = NextChar();
+ if (c < 0) {
+ return null;
+ }
+ if (!IsWS(c)) {
+ if (c == '(') {
+ if (stackEffect.IsKnown) {
+ Unread(c);
+ return null;
+ }
+ stackEffect = ParseStackEffectNF();
+ if (!stackEffect.IsKnown) {
+ return null;
+ }
+ continue;
+ } else if (c != '{') {
+ Unread(c);
+ return null;
+ }
+ break;
+ }
+ }
+ StringBuilder sb = new StringBuilder();
+ int count = 1;
+ for (;;) {
+ int c = NextChar();
+ if (c < 0) {
+ return null;
+ }
+ switch (c) {
+ case '{':
+ count ++;
+ break;
+ case '}':
+ if (-- count == 0) {
+ return sb.ToString();
+ }
+ break;
+ }
+ sb.Append((char)c);
+ }
+ }
+
+ /*
+ * Parse a stack effect declaration. This method assumes that the
+ * opening parenthesis has just been read. If the parsing fails,
+ * then this method returns SType.UNKNOWN.
+ */
+ SType ParseStackEffectNF()
+ {
+ bool seenSep = false;
+ bool seenBang = false;
+ int din = 0, dout = 0;
+ for (;;) {
+ string t = Next();
+ if (t == null) {
+ return SType.UNKNOWN;
+ }
+ if (t == "--") {
+ if (seenSep) {
+ return SType.UNKNOWN;
+ }
+ seenSep = true;
+ } else if (t == ")") {
+ if (seenSep) {
+ if (seenBang && dout == 1) {
+ dout = -1;
+ }
+ return new SType(din, dout);
+ } else {
+ return SType.UNKNOWN;
+ }
+ } else {
+ if (seenSep) {
+ if (dout == 0 && t == "!") {
+ seenBang = true;
+ }
+ dout ++;
+ } else {
+ din ++;
+ }
+ }
+ }
+ }
+
+ string ParseString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append('"');
+ bool lcwb = false;
+ int hexNum = 0;
+ int acc = 0;
+ for (;;) {
+ int c = NextChar();
+ if (c < 0) {
+ throw new Exception(
+ "Unfinished literal string");
+ }
+ if (hexNum > 0) {
+ int d = HexVal(c);
+ if (d < 0) {
+ throw new Exception(String.Format(
+ "not an hex digit: U+{0:X4}",
+ c));
+ }
+ acc = (acc << 4) + d;
+ if (-- hexNum == 0) {
+ sb.Append((char)acc);
+ acc = 0;
+ }
+ } else if (lcwb) {
+ lcwb = false;
+ switch (c) {
+ case '\n': SkipNL(); break;
+ case 'x':
+ hexNum = 2;
+ break;
+ case 'u':
+ hexNum = 4;
+ break;
+ default:
+ sb.Append(SingleCharEscape(c));
+ break;
+ }
+ } else {
+ switch (c) {
+ case '"':
+ return sb.ToString();
+ case '\\':
+ lcwb = true;
+ break;
+ default:
+ sb.Append((char)c);
+ break;
+ }
+ }
+ }
+ }
+
+ static char SingleCharEscape(int c)
+ {
+ switch (c) {
+ case 'n': return '\n';
+ case 'r': return '\r';
+ case 't': return '\t';
+ case 's': return ' ';
+ default:
+ return (char)c;
+ }
+ }
+
+ /*
+ * A backslash+newline sequence occurred in a literal string; we
+ * check and consume the newline escape sequence (whitespace at
+ * start of next line, then a double-quote character).
+ */
+ void SkipNL()
+ {
+ for (;;) {
+ int c = NextChar();
+ if (c < 0) {
+ throw new Exception("EOF in literal string");
+ }
+ if (c == '\n') {
+ throw new Exception(
+ "Unescaped newline in literal string");
+ }
+ if (IsWS(c)) {
+ continue;
+ }
+ if (c == '"') {
+ return;
+ }
+ throw new Exception(
+ "Invalid newline escape in literal string");
+ }
+ }
+
+ static char DecodeCharConst(string t)
+ {
+ if (t.Length == 1 && t[0] != '\\') {
+ return t[0];
+ }
+ if (t.Length >= 2 && t[0] == '\\') {
+ switch (t[1]) {
+ case 'x':
+ if (t.Length == 4) {
+ int x = DecHex(t.Substring(2));
+ if (x >= 0) {
+ return (char)x;
+ }
+ }
+ break;
+ case 'u':
+ if (t.Length == 6) {
+ int x = DecHex(t.Substring(2));
+ if (x >= 0) {
+ return (char)x;
+ }
+ }
+ break;
+ default:
+ if (t.Length == 2) {
+ return SingleCharEscape(t[1]);
+ }
+ break;
+ }
+ }
+ throw new Exception("Invalid literal char: `" + t);
+ }
+
+ static int DecHex(string s)
+ {
+ int acc = 0;
+ foreach (char c in s) {
+ int d = HexVal(c);
+ if (d < 0) {
+ return -1;
+ }
+ acc = (acc << 4) + d;
+ }
+ return acc;
+ }
+
+ static int HexVal(int c)
+ {
+ if (c >= '0' && c <= '9') {
+ return c - '0';
+ } else if (c >= 'A' && c <= 'F') {
+ return c - ('A' - 10);
+ } else if (c >= 'a' && c <= 'f') {
+ return c - ('a' - 10);
+ } else {
+ return -1;
+ }
+ }
+
+ string ReadTerm(int ct)
+ {
+ StringBuilder sb = new StringBuilder();
+ for (;;) {
+ int c = NextChar();
+ if (c < 0) {
+ throw new Exception(String.Format(
+ "EOF reached before U+{0:X4}", ct));
+ }
+ if (c == ct) {
+ return sb.ToString();
+ }
+ sb.Append((char)c);
+ }
+ }
+
+ static bool IsWS(int c)
+ {
+ return c <= 32;
+ }
+
+ void ProcessInput(TextReader tr)
+ {
+ this.currentInput = tr;
+ delayedChar = -1;
+ Word w = new WordNative(this, "toplevel",
+ xcpu => { CompileStep(xcpu); });
+ CPU cpu = new CPU();
+ Opcode[] code = new Opcode[] {
+ new OpcodeCall(w),
+ new OpcodeJumpUncond(-2)
+ };
+ quitRunLoop = false;
+ cpu.Enter(code, 0);
+ for (;;) {
+ if (quitRunLoop) {
+ break;
+ }
+ Opcode op = cpu.ipBuf[cpu.ipOff ++];
+ op.Run(cpu);
+ }
+ }
+
+ void CompileStep(CPU cpu)
+ {
+ string tt = Next();
+ if (tt == null) {
+ if (compiling) {
+ throw new Exception("EOF while compiling");
+ }
+ quitRunLoop = true;
+ return;
+ }
+ TValue v;
+ bool isVal = TryParseLiteral(tt, out v);
+ Word w = LookupNF(tt);
+ if (isVal && w != null) {
+ throw new Exception(String.Format(
+ "Ambiguous: both defined word and literal: {0}",
+ tt));
+ }
+ if (compiling) {
+ if (isVal) {
+ wordBuilder.Literal(v);
+ } else if (w != null) {
+ if (w.Immediate) {
+ w.Run(cpu);
+ } else {
+ wordBuilder.CallExt(w);
+ }
+ } else {
+ wordBuilder.Call(tt);
+ }
+ } else {
+ if (isVal) {
+ cpu.Push(v);
+ } else if (w != null) {
+ w.Run(cpu);
+ } else {
+ throw new Exception(String.Format(
+ "Unknown word: '{0}'", tt));
+ }
+ }
+ }
+
+ string GetCCode(string name)
+ {
+ string ccode;
+ allCCode.TryGetValue(name, out ccode);
+ return ccode;
+ }
+
+ void Generate(string outBase, string coreRun,
+ params string[] entryPoints)
+ {
+ /*
+ * Gather all words that are part of the generated
+ * code. This is done by exploring references
+ * transitively. All such words are thus implicitly
+ * resolved.
+ */
+ IDictionary<string, Word> wordSet =
+ new SortedDictionary<string, Word>(
+ StringComparer.Ordinal);
+ Queue<Word> tx = new Queue<Word>();
+ foreach (string ep in entryPoints) {
+ if (wordSet.ContainsKey(ep)) {
+ continue;
+ }
+ Word w = Lookup(ep);
+ wordSet[w.Name] = w;
+ tx.Enqueue(w);
+ }
+ while (tx.Count > 0) {
+ Word w = tx.Dequeue();
+ foreach (Word w2 in w.GetReferences()) {
+ if (wordSet.ContainsKey(w2.Name)) {
+ continue;
+ }
+ wordSet[w2.Name] = w2;
+ tx.Enqueue(w2);
+ }
+ }
+
+ /*
+ * Do flow analysis.
+ */
+ if (enableFlowAnalysis) {
+ foreach (string ep in entryPoints) {
+ Word w = wordSet[ep];
+ w.AnalyseFlow();
+ Console.WriteLine("{0}: ds={1} rs={2}",
+ ep, w.MaxDataStack, w.MaxReturnStack);
+ if (w.MaxDataStack > dsLimit) {
+ throw new Exception("'" + ep
+ + "' exceeds data stack limit");
+ }
+ if (w.MaxReturnStack > rsLimit) {
+ throw new Exception("'" + ep
+ + "' exceeds return stack"
+ + " limit");
+ }
+ }
+ }
+
+ /*
+ * Gather referenced data areas and compute their
+ * addresses in the generated data block. The address
+ * 0 in the data block is unaffected so that no
+ * valid runtime pointer is equal to null.
+ */
+ IDictionary<long, ConstData> blocks =
+ new SortedDictionary<long, ConstData>();
+ foreach (Word w in wordSet.Values) {
+ foreach (ConstData cd in w.GetDataBlocks()) {
+ blocks[cd.ID] = cd;
+ }
+ }
+ int dataLen = 1;
+ foreach (ConstData cd in blocks.Values) {
+ cd.Address = dataLen;
+ dataLen += cd.Length;
+ }
+
+ /*
+ * Generated code is a sequence of "slot numbers", each
+ * referencing either a piece of explicit C code, or an
+ * entry in the table of interpreted words.
+ *
+ * Opcodes other than "call" get the slots 0 to 6:
+ *
+ * 0 ret no argument
+ * 1 const signed value
+ * 2 get local local number
+ * 3 put local local number
+ * 4 jump signed offset
+ * 5 jump if signed offset
+ * 6 jump if not signed offset
+ *
+ * The argument, if any, is in "7E" format: the value is
+ * encoded in 7-bit chunk, with big-endian signed
+ * convention. Each 7-bit chunk is encoded over one byte;
+ * the upper bit is 1 for all chunks except the last one.
+ *
+ * Words with explicit C code get the slot numbers
+ * immediately after 6. Interpreted words come afterwards.
+ */
+ IDictionary<string, int> slots = new Dictionary<string, int>();
+ int curSlot = 7;
+
+ /*
+ * Get explicit C code for words which have such code.
+ * We use string equality on C code so that words with
+ * identical implementations get merged.
+ *
+ * We also check that words with no explicit C code are
+ * interpreted.
+ */
+ IDictionary<string, int> ccodeUni =
+ new Dictionary<string, int>();
+ IDictionary<int, string> ccodeNames =
+ new Dictionary<int, string>();
+ foreach (Word w in wordSet.Values) {
+ string ccode = GetCCode(w.Name);
+ if (ccode == null) {
+ if (w is WordNative) {
+ throw new Exception(String.Format(
+ "No C code for native '{0}'",
+ w.Name));
+ }
+ continue;
+ }
+ int sn;
+ if (ccodeUni.ContainsKey(ccode)) {
+ sn = ccodeUni[ccode];
+ ccodeNames[sn] += " " + EscapeCComment(w.Name);
+ } else {
+ sn = curSlot ++;
+ ccodeUni[ccode] = sn;
+ ccodeNames[sn] = EscapeCComment(w.Name);
+ }
+ slots[w.Name] = sn;
+ w.Slot = sn;
+ }
+
+ /*
+ * Assign slot values to all remaining words; we know they
+ * are all interpreted.
+ */
+ int slotInterpreted = curSlot;
+ foreach (Word w in wordSet.Values) {
+ if (GetCCode(w.Name) != null) {
+ continue;
+ }
+ int sn = curSlot ++;
+ slots[w.Name] = sn;
+ w.Slot = sn;
+ }
+ int numInterpreted = curSlot - slotInterpreted;
+
+ /*
+ * Verify that all entry points are interpreted words.
+ */
+ foreach (string ep in entryPoints) {
+ if (GetCCode(ep) != null) {
+ throw new Exception(
+ "Non-interpreted entry point");
+ }
+ }
+
+ /*
+ * Compute the code block. Each word (without any C code)
+ * yields some CodeElement instances.
+ */
+ List<CodeElement> gcodeList = new List<CodeElement>();
+ CodeElement[] interpretedEntry =
+ new CodeElement[numInterpreted];
+ foreach (Word w in wordSet.Values) {
+ if (GetCCode(w.Name) != null) {
+ continue;
+ }
+ int n = gcodeList.Count;
+ w.GenerateCodeElements(gcodeList);
+ interpretedEntry[w.Slot - slotInterpreted] =
+ gcodeList[n];
+ }
+ CodeElement[] gcode = gcodeList.ToArray();
+
+ /*
+ * If there are less than 256 words in total (C +
+ * interpreted) then we can use "one-byte code" which is
+ * more compact when the number of words is in the
+ * 128..255 range.
+ */
+ bool oneByteCode;
+ if (slotInterpreted + numInterpreted >= 256) {
+ Console.WriteLine("WARNING: more than 255 words");
+ oneByteCode = false;
+ } else {
+ oneByteCode = true;
+ }
+
+ /*
+ * Compute all addresses and offsets. This loops until
+ * the addresses stabilize.
+ */
+ int totalLen = -1;
+ int[] gcodeLen = new int[gcode.Length];
+ for (;;) {
+ for (int i = 0; i < gcode.Length; i ++) {
+ gcodeLen[i] = gcode[i].GetLength(oneByteCode);
+ }
+ int off = 0;
+ for (int i = 0; i < gcode.Length; i ++) {
+ gcode[i].Address = off;
+ gcode[i].LastLength = gcodeLen[i];
+ off += gcodeLen[i];
+ }
+ if (off == totalLen) {
+ break;
+ }
+ totalLen = off;
+ }
+
+ /*
+ * Produce output file.
+ */
+ using (TextWriter tw = File.CreateText(outBase + ".c")) {
+ tw.NewLine = "\n";
+
+ tw.WriteLine("{0}",
+@"/* Automatically generated code; do not modify directly. */
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct {
+ uint32_t *dp;
+ uint32_t *rp;
+ const unsigned char *ip;
+} t0_context;
+
+static uint32_t
+t0_parse7E_unsigned(const unsigned char **p)
+{
+ uint32_t x;
+
+ x = 0;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ return x;
+ }
+ }
+}
+
+static int32_t
+t0_parse7E_signed(const unsigned char **p)
+{
+ int neg;
+ uint32_t x;
+
+ neg = ((**p) >> 6) & 1;
+ x = (uint32_t)-neg;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ if (neg) {
+ return -(int32_t)~x - 1;
+ } else {
+ return (int32_t)x;
+ }
+ }
+ }
+}
+
+#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80)
+#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F)
+#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8)
+#define T0_INT1(x) T0_FBYTE(x, 0)
+#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+
+/* static const unsigned char t0_datablock[]; */
+");
+
+ /*
+ * Add declarations (not definitions) for the
+ * entry point initialisation functions, and the
+ * runner.
+ */
+ tw.WriteLine();
+ foreach (string ep in entryPoints) {
+ tw.WriteLine("void {0}_init_{1}(void *t0ctx);",
+ coreRun, ep);
+ }
+ tw.WriteLine();
+ tw.WriteLine("void {0}_run(void *t0ctx);", coreRun);
+
+ /*
+ * Add preamble elements here. They may be needed
+ * for evaluating constant expressions in the
+ * code block.
+ */
+ foreach (string pp in extraCode) {
+ tw.WriteLine();
+ tw.WriteLine("{0}", pp);
+ }
+
+ BlobWriter bw;
+ tw.WriteLine();
+ tw.Write("static const unsigned char"
+ + " t0_datablock[] = {");
+ bw = new BlobWriter(tw, 78, 1);
+ bw.Append((byte)0);
+ foreach (ConstData cd in blocks.Values) {
+ cd.Encode(bw);
+ }
+ tw.WriteLine();
+ tw.WriteLine("};");
+
+ tw.WriteLine();
+ tw.Write("static const unsigned char"
+ + " t0_codeblock[] = {");
+ bw = new BlobWriter(tw, 78, 1);
+ foreach (CodeElement ce in gcode) {
+ ce.Encode(bw, oneByteCode);
+ }
+ tw.WriteLine();
+ tw.WriteLine("};");
+
+ tw.WriteLine();
+ tw.Write("static const uint16_t t0_caddr[] = {");
+ for (int i = 0; i < interpretedEntry.Length; i ++) {
+ if (i != 0) {
+ tw.Write(',');
+ }
+ tw.WriteLine();
+ tw.Write("\t{0}", interpretedEntry[i].Address);
+ }
+ tw.WriteLine();
+ tw.WriteLine("};");
+
+ tw.WriteLine();
+ tw.WriteLine("#define T0_INTERPRETED {0}",
+ slotInterpreted);
+ tw.WriteLine();
+ tw.WriteLine("{0}",
+@"#define T0_ENTER(ip, rp, slot) do { \
+ const unsigned char *t0_newip; \
+ uint32_t t0_lnum; \
+ t0_newip = &t0_codeblock[t0_caddr[(slot) - T0_INTERPRETED]]; \
+ t0_lnum = t0_parse7E_unsigned(&t0_newip); \
+ (rp) += t0_lnum; \
+ *((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \
+ (ip) = t0_newip; \
+ } while (0)");
+ tw.WriteLine();
+ tw.WriteLine("{0}",
+@"#define T0_DEFENTRY(name, slot) \
+void \
+name(void *ctx) \
+{ \
+ t0_context *t0ctx = ctx; \
+ t0ctx->ip = &t0_codeblock[0]; \
+ T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \
+}");
+
+ tw.WriteLine();
+ foreach (string ep in entryPoints) {
+ tw.WriteLine("T0_DEFENTRY({0}, {1})",
+ coreRun + "_init_" + ep,
+ wordSet[ep].Slot);
+ }
+ tw.WriteLine();
+ if (oneByteCode) {
+ tw.WriteLine("{0}",
+@"#define T0_NEXT(t0ipp) (*(*(t0ipp)) ++)");
+ } else {
+ tw.WriteLine("{0}",
+@"#define T0_NEXT(t0ipp) t0_parse7E_unsigned(t0ipp)");
+ }
+ tw.WriteLine();
+ tw.WriteLine("void");
+ tw.WriteLine("{0}_run(void *t0ctx)", coreRun);
+ tw.WriteLine("{0}",
+@"{
+ uint32_t *dp, *rp;
+ const unsigned char *ip;
+
+#define T0_LOCAL(x) (*(rp - 2 - (x)))
+#define T0_POP() (*-- dp)
+#define T0_POPi() (*(int32_t *)(-- dp))
+#define T0_PEEK(x) (*(dp - 1 - (x)))
+#define T0_PEEKi(x) (*(int32_t *)(dp - 1 - (x)))
+#define T0_PUSH(v) do { *dp = (v); dp ++; } while (0)
+#define T0_PUSHi(v) do { *(int32_t *)dp = (v); dp ++; } while (0)
+#define T0_RPOP() (*-- rp)
+#define T0_RPOPi() (*(int32_t *)(-- rp))
+#define T0_RPUSH(v) do { *rp = (v); rp ++; } while (0)
+#define T0_RPUSHi(v) do { *(int32_t *)rp = (v); rp ++; } while (0)
+#define T0_ROLL(x) do { \
+ size_t t0len = (size_t)(x); \
+ uint32_t t0tmp = *(dp - 1 - t0len); \
+ memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_SWAP() do { \
+ uint32_t t0tmp = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_ROT() do { \
+ uint32_t t0tmp = *(dp - 3); \
+ *(dp - 3) = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_NROT() do { \
+ uint32_t t0tmp = *(dp - 1); \
+ *(dp - 1) = *(dp - 2); \
+ *(dp - 2) = *(dp - 3); \
+ *(dp - 3) = t0tmp; \
+} while (0)
+#define T0_PICK(x) do { \
+ uint32_t t0depth = (x); \
+ T0_PUSH(T0_PEEK(t0depth)); \
+} while (0)
+#define T0_CO() do { \
+ goto t0_exit; \
+} while (0)
+#define T0_RET() goto t0_next
+
+ dp = ((t0_context *)t0ctx)->dp;
+ rp = ((t0_context *)t0ctx)->rp;
+ ip = ((t0_context *)t0ctx)->ip;
+ goto t0_next;
+ for (;;) {
+ uint32_t t0x;
+
+ t0_next:
+ t0x = T0_NEXT(&ip);
+ if (t0x < T0_INTERPRETED) {
+ switch (t0x) {
+ int32_t t0off;
+
+ case 0: /* ret */
+ t0x = T0_RPOP();
+ rp -= (t0x >> 16);
+ t0x &= 0xFFFF;
+ if (t0x == 0) {
+ ip = NULL;
+ goto t0_exit;
+ }
+ ip = &t0_codeblock[t0x];
+ break;
+ case 1: /* literal constant */
+ T0_PUSHi(t0_parse7E_signed(&ip));
+ break;
+ case 2: /* read local */
+ T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip)));
+ break;
+ case 3: /* write local */
+ T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP();
+ break;
+ case 4: /* jump */
+ t0off = t0_parse7E_signed(&ip);
+ ip += t0off;
+ break;
+ case 5: /* jump if */
+ t0off = t0_parse7E_signed(&ip);
+ if (T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 6: /* jump if not */
+ t0off = t0_parse7E_signed(&ip);
+ if (!T0_POP()) {
+ ip += t0off;
+ }
+ break;");
+
+ SortedDictionary<int, string> nccode =
+ new SortedDictionary<int, string>();
+ foreach (string k in ccodeUni.Keys) {
+ nccode[ccodeUni[k]] = k;
+ }
+ foreach (int sn in nccode.Keys) {
+ tw.WriteLine(
+@" case {0}: {{
+ /* {1} */
+{2}
+ }}
+ break;", sn, ccodeNames[sn], nccode[sn]);
+ }
+
+ tw.WriteLine(
+@" }
+
+ } else {
+ T0_ENTER(ip, rp, t0x);
+ }
+ }
+t0_exit:
+ ((t0_context *)t0ctx)->dp = dp;
+ ((t0_context *)t0ctx)->rp = rp;
+ ((t0_context *)t0ctx)->ip = ip;
+}");
+
+ /*
+ * Add the "postamblr" elements here. These are
+ * elements that may need access to the data
+ * block or code block, so they must occur after
+ * their definition.
+ */
+ foreach (string pp in extraCodeDefer) {
+ tw.WriteLine();
+ tw.WriteLine("{0}", pp);
+ }
+ }
+
+ int codeLen = 0;
+ foreach (CodeElement ce in gcode) {
+ codeLen += ce.GetLength(oneByteCode);
+ }
+ int dataBlockLen = 0;
+ foreach (ConstData cd in blocks.Values) {
+ dataBlockLen += cd.Length;
+ }
+
+ /*
+ * Write some statistics on produced code.
+ */
+ Console.WriteLine("code length: {0,6} byte(s)", codeLen);
+ Console.WriteLine("data length: {0,6} byte(s)", dataLen);
+ Console.WriteLine("total words: {0} (interpreted: {1})",
+ slotInterpreted + numInterpreted, numInterpreted);
+ }
+
+ internal Word Lookup(string name)
+ {
+ Word w = LookupNF(name);
+ if (w != null) {
+ return w;
+ }
+ throw new Exception(String.Format("No such word: '{0}'", name));
+ }
+
+ internal Word LookupNF(string name)
+ {
+ Word w;
+ words.TryGetValue(name, out w);
+ return w;
+ }
+
+ internal TValue StringToBlob(string s)
+ {
+ return new TValue(0, new TPointerBlob(this, s));
+ }
+
+ internal bool TryParseLiteral(string tt, out TValue tv)
+ {
+ tv = new TValue(0);
+ if (tt.StartsWith("\"")) {
+ tv = StringToBlob(tt.Substring(1));
+ return true;
+ }
+ if (tt.StartsWith("`")) {
+ tv = DecodeCharConst(tt.Substring(1));
+ return true;
+ }
+ bool neg = false;
+ if (tt.StartsWith("-")) {
+ neg = true;
+ tt = tt.Substring(1);
+ } else if (tt.StartsWith("+")) {
+ tt = tt.Substring(1);
+ }
+ uint radix = 10;
+ if (tt.StartsWith("0x") || tt.StartsWith("0X")) {
+ radix = 16;
+ tt = tt.Substring(2);
+ } else if (tt.StartsWith("0b") || tt.StartsWith("0B")) {
+ radix = 2;
+ tt = tt.Substring(2);
+ }
+ if (tt.Length == 0) {
+ return false;
+ }
+ uint acc = 0;
+ bool overflow = false;
+ uint maxV = uint.MaxValue / radix;
+ foreach (char c in tt) {
+ int d = HexVal(c);
+ if (d < 0 || d >= radix) {
+ return false;
+ }
+ if (acc > maxV) {
+ overflow = true;
+ }
+ acc *= radix;
+ if ((uint)d > uint.MaxValue - acc) {
+ overflow = true;
+ }
+ acc += (uint)d;
+ }
+ int x = (int)acc;
+ if (neg) {
+ if (acc > (uint)0x80000000) {
+ overflow = true;
+ }
+ x = -x;
+ }
+ if (overflow) {
+ throw new Exception(
+ "invalid literal integer (overflow)");
+ }
+ tv = x;
+ return true;
+ }
+
+ int ParseInteger(string tt)
+ {
+ TValue tv;
+ if (!TryParseLiteral(tt, out tv)) {
+ throw new Exception("not an integer: " + ToString());
+ }
+ return (int)tv;
+ }
+
+ void CheckCompiling()
+ {
+ if (!compiling) {
+ throw new Exception("Not in compilation mode");
+ }
+ }
+
+ static string EscapeCComment(string s)
+ {
+ StringBuilder sb = new StringBuilder();
+ foreach (char c in s) {
+ if (c >= 33 && c <= 126 && c != '%') {
+ sb.Append(c);
+ } else if (c < 0x100) {
+ sb.AppendFormat("%{0:X2}", (int)c);
+ } else if (c < 0x800) {
+ sb.AppendFormat("%{0:X2}%{0:X2}",
+ ((int)c >> 6) | 0xC0,
+ ((int)c & 0x3F) | 0x80);
+ } else {
+ sb.AppendFormat("%{0:X2}%{0:X2}%{0:X2}",
+ ((int)c >> 12) | 0xE0,
+ (((int)c >> 6) & 0x3F) | 0x80,
+ ((int)c & 0x3F) | 0x80);
+ }
+ }
+ return sb.ToString().Replace("*/", "%2A/");
+ }
+}
diff --git a/T0/TPointerBase.cs b/T0/TPointerBase.cs
new file mode 100644
index 000000000000..f996d8d878cf
--- /dev/null
+++ b/T0/TPointerBase.cs
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class TPointerBase {
+
+ /* obsolete
+ internal virtual TValue Get(TValue vp)
+ {
+ throw new Exception(
+ "cannot get values from this pointer");
+ }
+
+ internal virtual void Set(TValue vp, TValue nval)
+ {
+ throw new Exception(
+ "cannot set values to this pointer");
+ }
+ */
+
+ internal virtual bool ToBool(TValue vp)
+ {
+ return true;
+ }
+
+ internal virtual void Execute(T0Comp ctx, CPU cpu)
+ {
+ throw new Exception("value is not an xt: " + ToString());
+ }
+
+ internal virtual string ToString(TValue vp)
+ {
+ return String.Format("{0}+{1}",
+ GetType().Name, vp.x);
+ }
+
+ internal virtual bool Equals(TPointerBase tp)
+ {
+ return this == tp;
+ }
+}
diff --git a/T0/TPointerBlob.cs b/T0/TPointerBlob.cs
new file mode 100644
index 000000000000..d4aeff647c52
--- /dev/null
+++ b/T0/TPointerBlob.cs
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class TPointerBlob : TPointerBase {
+
+ internal ConstData Blob { get; private set; }
+
+ internal TPointerBlob(ConstData cd)
+ {
+ this.Blob = cd;
+ }
+
+ internal TPointerBlob(T0Comp owner, string s)
+ {
+ Blob = new ConstData(owner);
+ Blob.AddString(s);
+ }
+
+ /* obsolete
+ internal override TValue Get8(TValue vp)
+ {
+ return new TValue((int)Blob.Read8(vp.x));
+ }
+
+ internal override TValue Get16(TValue vp)
+ {
+ return new TValue((int)Blob.Read16(vp.x));
+ }
+
+ internal override TValue Get24(TValue vp)
+ {
+ return new TValue((int)Blob.Read24(vp.x));
+ }
+
+ internal override TValue Get32(TValue vp)
+ {
+ return new TValue((int)Blob.Read32(vp.x));
+ }
+ */
+
+ internal override string ToString(TValue vp)
+ {
+ return Blob.ToString(vp.x);
+ }
+
+ internal override bool Equals(TPointerBase tp)
+ {
+ TPointerBlob tb = tp as TPointerBlob;
+ return tb != null && Blob == tb.Blob;
+ }
+}
diff --git a/T0/TPointerExpr.cs b/T0/TPointerExpr.cs
new file mode 100644
index 000000000000..314b27208971
--- /dev/null
+++ b/T0/TPointerExpr.cs
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+
+class TPointerExpr : TPointerBase {
+
+ string expr;
+ int min, max;
+
+ internal TPointerExpr(string expr, int min, int max)
+ {
+ this.expr = expr;
+ this.min = min;
+ this.max = max;
+ }
+
+ internal override bool ToBool(TValue vp)
+ {
+ throw new Exception("Cannot evaluate C-expr at compile time");
+ }
+
+ internal override string ToString(TValue vp)
+ {
+ return ToCExpr(vp.x);
+ }
+
+ internal string ToCExpr(int off)
+ {
+ if (off == 0) {
+ return expr;
+ } else if (off > 0) {
+ return String.Format(
+ "(uint32_t)({0}) + {1}", expr, off);
+ } else {
+ return String.Format(
+ "(uint32_t)({0}) - {1}", expr, -(long)off);
+ }
+ }
+
+ internal int GetMaxBitLength(int off)
+ {
+ long rmin = (long)min + off;
+ long rmax = (long)max + off;
+ int numBits = 1;
+ if (rmin < 0) {
+ numBits = Math.Max(numBits, BitLength(rmin));
+ }
+ if (rmax > 0) {
+ numBits = Math.Max(numBits, BitLength(rmax));
+ }
+ return Math.Min(numBits, 32);
+ }
+
+ /*
+ * Get the minimal bit length of a value. This is for a signed
+ * representation: the length includes a sign bit. Thus, the
+ * returned value will be at least 1.
+ */
+ static int BitLength(long v)
+ {
+ int num = 1;
+ if (v < 0) {
+ while (v != -1) {
+ num ++;
+ v >>= 1;
+ }
+ } else {
+ while (v != 0) {
+ num ++;
+ v >>= 1;
+ }
+ }
+ return num;
+ }
+}
diff --git a/T0/TPointerNull.cs b/T0/TPointerNull.cs
new file mode 100644
index 000000000000..f8eb11e42f20
--- /dev/null
+++ b/T0/TPointerNull.cs
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class TPointerNull : TPointerBase {
+
+ internal override bool ToBool(TValue vp)
+ {
+ return false;
+ }
+
+ internal override string ToString(TValue vp)
+ {
+ return "null";
+ }
+
+ internal override bool Equals(TPointerBase tp)
+ {
+ return tp is TPointerNull;
+ }
+}
diff --git a/T0/TPointerXT.cs b/T0/TPointerXT.cs
new file mode 100644
index 000000000000..883f31296417
--- /dev/null
+++ b/T0/TPointerXT.cs
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class TPointerXT : TPointerBase {
+
+ internal string Name {
+ get; private set;
+ }
+
+ internal Word Target {
+ get; private set;
+ }
+
+ internal TPointerXT(string name)
+ {
+ this.Name = name;
+ this.Target = null;
+ }
+
+ internal TPointerXT(Word target)
+ {
+ this.Name = target.Name;
+ this.Target = target;
+ }
+
+ internal void Resolve(T0Comp ctx)
+ {
+ if (Target == null) {
+ Target = ctx.Lookup(Name);
+ }
+ }
+
+ internal override void Execute(T0Comp ctx, CPU cpu)
+ {
+ Resolve(ctx);
+ Target.Run(cpu);
+ }
+
+ internal override string ToString(TValue vp)
+ {
+ return String.Format("<'{0}>", Name);
+ }
+
+ internal override bool Equals(TPointerBase tp)
+ {
+ TPointerXT tx = tp as TPointerXT;
+ return tx != null && Name == tx.Name;
+ }
+}
diff --git a/T0/TValue.cs b/T0/TValue.cs
new file mode 100644
index 000000000000..e4f225574c8e
--- /dev/null
+++ b/T0/TValue.cs
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+/*
+ * Each value is represented with a TValue structure. Integers use the 'x'
+ * field, and 'ptr' is null; for pointers, the 'ptr' field is used, and the
+ * 'x' is then an offset in the object represented by 'ptr'.
+ */
+
+struct TValue {
+
+ internal int x;
+ internal TPointerBase ptr;
+
+ internal TValue(int x)
+ {
+ this.x = x;
+ this.ptr = null;
+ }
+
+ internal TValue(uint x)
+ {
+ this.x = (int)x;
+ this.ptr = null;
+ }
+
+ internal TValue(bool b)
+ {
+ this.x = b ? -1 : 0;
+ this.ptr = null;
+ }
+
+ internal TValue(int x, TPointerBase ptr)
+ {
+ this.x = x;
+ this.ptr = ptr;
+ }
+
+ /*
+ * Convert this value to a boolean; integer 0 and null pointer are
+ * 'false', other values are 'true'.
+ */
+ internal bool Bool {
+ get {
+ if (ptr == null) {
+ return x != 0;
+ } else {
+ return ptr.ToBool(this);
+ }
+ }
+ }
+
+ /*
+ * Get this value as an integer. Pointers cannot be converted to
+ * integers.
+ */
+ internal int Int {
+ get {
+ if (ptr == null) {
+ return x;
+ }
+ throw new Exception("not an integer: " + ToString());
+ }
+ }
+
+ /*
+ * Get this value as an unsigned integer. This is the integer
+ * value, reduced modulo 2^32 in the 0..2^32-1 range.
+ */
+ internal uint UInt {
+ get {
+ return (uint)Int;
+ }
+ }
+
+ /*
+ * String format of integers uses decimal representation. For
+ * pointers, this depends on the pointed-to value.
+ */
+ public override string ToString()
+ {
+ if (ptr == null) {
+ return String.Format("{0}", x);
+ } else {
+ return ptr.ToString(this);
+ }
+ }
+
+ /*
+ * If this value is an XT, then execute it. Otherwise, an exception
+ * is thrown.
+ */
+ internal void Execute(T0Comp ctx, CPU cpu)
+ {
+ ToXT().Execute(ctx, cpu);
+ }
+
+ /*
+ * Convert this value to an XT. On failure, an exception is thrown.
+ */
+ internal TPointerXT ToXT()
+ {
+ TPointerXT xt = ptr as TPointerXT;
+ if (xt == null) {
+ throw new Exception(
+ "value is not an xt: " + ToString());
+ }
+ return xt;
+ }
+
+ /*
+ * Compare this value to another.
+ */
+ internal bool Equals(TValue v)
+ {
+ if (x != v.x) {
+ return false;
+ }
+ if (ptr == v.ptr) {
+ return true;
+ }
+ if (ptr == null || v.ptr == null) {
+ return false;
+ }
+ return ptr.Equals(v.ptr);
+ }
+
+ public static implicit operator TValue(bool val)
+ {
+ return new TValue(val);
+ }
+
+ public static implicit operator TValue(sbyte val)
+ {
+ return new TValue((int)val);
+ }
+
+ public static implicit operator TValue(byte val)
+ {
+ return new TValue((int)val);
+ }
+
+ public static implicit operator TValue(short val)
+ {
+ return new TValue((int)val);
+ }
+
+ public static implicit operator TValue(ushort val)
+ {
+ return new TValue((int)val);
+ }
+
+ public static implicit operator TValue(char val)
+ {
+ return new TValue((int)val);
+ }
+
+ public static implicit operator TValue(int val)
+ {
+ return new TValue((int)val);
+ }
+
+ public static implicit operator TValue(uint val)
+ {
+ return new TValue((int)val);
+ }
+
+ public static implicit operator bool(TValue v)
+ {
+ return v.Bool;
+ }
+
+ public static implicit operator sbyte(TValue v)
+ {
+ return (sbyte)v.Int;
+ }
+
+ public static implicit operator byte(TValue v)
+ {
+ return (byte)v.Int;
+ }
+
+ public static implicit operator short(TValue v)
+ {
+ return (short)v.Int;
+ }
+
+ public static implicit operator ushort(TValue v)
+ {
+ return (ushort)v.Int;
+ }
+
+ public static implicit operator char(TValue v)
+ {
+ return (char)v.Int;
+ }
+
+ public static implicit operator int(TValue v)
+ {
+ return (int)v.Int;
+ }
+
+ public static implicit operator uint(TValue v)
+ {
+ return (uint)v.Int;
+ }
+}
diff --git a/T0/Word.cs b/T0/Word.cs
new file mode 100644
index 000000000000..2dfb66ef0691
--- /dev/null
+++ b/T0/Word.cs
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+/*
+ * A "word" is a function with a name. Words can be either native or
+ * interpreted; native words are implemented as some in-compiler special
+ * code.
+ *
+ * Some native words (not all of them) have a C implementation and can
+ * thus be part of the generated C code. Native words with no C
+ * implementation can be used only during compilation; this is typically
+ * the case for words that support the syntax (e.g. 'if').
+ */
+
+abstract class Word {
+
+ /*
+ * The compiler context for this word.
+ */
+ internal T0Comp TC {
+ get; private set;
+ }
+
+ /*
+ * Immediate words are executed immediately when encountered in the
+ * source code, even while compiling another word.
+ */
+ internal bool Immediate {
+ get; set;
+ }
+
+ /*
+ * Each word has a unique name. Names are case-sensitive.
+ */
+ internal string Name {
+ get; private set;
+ }
+
+ /*
+ * Words are allocated slot numbers when output code is generated.
+ */
+ internal int Slot {
+ get; set;
+ }
+
+ /*
+ * Each word may have a known stack effect.
+ */
+ internal SType StackEffect {
+ get; set;
+ }
+
+ internal Word(T0Comp owner, string name)
+ {
+ TC = owner;
+ Name = name;
+ StackEffect = SType.UNKNOWN;
+ }
+
+ /*
+ * Resolving a word means looking up all references to external
+ * words.
+ */
+ internal virtual void Resolve()
+ {
+ }
+
+ /*
+ * Execute this word. If the word is native, then its code is
+ * run right away; if the word is interpreted, then the entry
+ * sequence is executed.
+ */
+ internal virtual void Run(CPU cpu)
+ {
+ throw new Exception(String.Format(
+ "cannot run '{0}' at compile-time", Name));
+ }
+
+ /*
+ * All words may have an explicit C implementations. To be part
+ * of the generated C code, a word must either be interpreted,
+ * or have an explicit C implementation, or both.
+ */
+ internal string CCode {
+ get; set;
+ }
+
+ /*
+ * Get all words referenced from this one. This implies
+ * resolving the word.
+ */
+ internal virtual List<Word> GetReferences()
+ {
+ return new List<Word>();
+ }
+
+ /*
+ * Get all data blocks directly referenced from this one. This
+ * implies resolving the word.
+ */
+ internal virtual List<ConstData> GetDataBlocks()
+ {
+ return new List<ConstData>();
+ }
+
+ /*
+ * Produce the code elements for this word.
+ */
+ internal virtual void GenerateCodeElements(List<CodeElement> dst)
+ {
+ throw new Exception("Word does not yield code elements");
+ }
+
+ /*
+ * Compute/verify stack effect for this word.
+ */
+ internal virtual void AnalyseFlow()
+ {
+ }
+
+ /*
+ * Get maximum data stack usage for this word. This is the number
+ * of extra slots that this word may need on the data stack. If
+ * the stack effect is not known, this returns -1.
+ */
+ internal virtual int MaxDataStack {
+ get {
+ SType se = StackEffect;
+ if (!se.IsKnown) {
+ return -1;
+ }
+ if (se.NoExit) {
+ return 0;
+ } else {
+ return Math.Min(0, se.DataOut - se.DataIn);
+ }
+ }
+ }
+
+ /*
+ * Get maximum return stack usage for this word.
+ */
+ internal virtual int MaxReturnStack {
+ get {
+ return 0;
+ }
+ }
+}
diff --git a/T0/WordBuilder.cs b/T0/WordBuilder.cs
new file mode 100644
index 000000000000..c410930eab78
--- /dev/null
+++ b/T0/WordBuilder.cs
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+/*
+ * A WordBuilder instance organizes construction of a new interpreted word.
+ *
+ * Opcodes are accumulated with specific methods. A control-flow stack
+ * is maintained to resolve jumps.
+ *
+ * Each instance shall be used for only one word.
+ */
+
+class WordBuilder {
+
+ T0Comp TC;
+ string name;
+ int[] cfStack;
+ int cfPtr;
+ List<Opcode> code;
+ List<string> toResolve;
+ Dictionary<string, int> locals;
+ bool jumpToLast;
+
+ internal SType StackEffect {
+ get; set;
+ }
+
+ /*
+ * Create a new instance, with the specified word name.
+ */
+ internal WordBuilder(T0Comp TC, string name)
+ {
+ this.TC = TC;
+ this.name = name;
+ cfStack = new int[16];
+ cfPtr = -1;
+ code = new List<Opcode>();
+ toResolve = new List<string>();
+ locals = new Dictionary<string, int>();
+ jumpToLast = true;
+ StackEffect = SType.UNKNOWN;
+ }
+
+ /*
+ * Build the word. The control-flow stack must be empty. A 'ret'
+ * opcode is automatically appended if required.
+ */
+ internal Word Build()
+ {
+ if (cfPtr != -1) {
+ throw new Exception("control-flow stack is not empty");
+ }
+ if (jumpToLast || code[code.Count - 1].MayFallThrough) {
+ Ret();
+ }
+ Word w = new WordInterpreted(TC, name, locals.Count,
+ code.ToArray(), toResolve.ToArray());
+ w.StackEffect = StackEffect;
+ return w;
+ }
+
+ void Add(Opcode op)
+ {
+ Add(op, null);
+ }
+
+ void Add(Opcode op, string refName)
+ {
+ code.Add(op);
+ toResolve.Add(refName);
+ jumpToLast = false;
+ }
+
+ /*
+ * Rotate the control-flow stack at depth 'depth'.
+ */
+ internal void CSRoll(int depth)
+ {
+ int x = cfStack[cfPtr - depth];
+ Array.Copy(cfStack, cfPtr - (depth - 1),
+ cfStack, cfPtr - depth, depth);
+ cfStack[cfPtr] = x;
+ }
+
+ /*
+ * Make a copy of the control-flow element at depth 'depth', and
+ * push it on top of the control-flow stack.
+ */
+ internal void CSPick(int depth)
+ {
+ int x = cfStack[cfPtr - depth];
+ CSPush(x);
+ }
+
+ void CSPush(int x)
+ {
+ int len = cfStack.Length;
+ if (++ cfPtr == len) {
+ int[] ncf = new int[len << 1];
+ Array.Copy(cfStack, 0, ncf, 0, len);
+ cfStack = ncf;
+ }
+ cfStack[cfPtr] = x;
+ }
+
+ int CSPop()
+ {
+ return cfStack[cfPtr --];
+ }
+
+ /*
+ * Push an origin on the control-flow stack, corresponding to the
+ * next opcode to add.
+ */
+ internal void CSPushOrig()
+ {
+ CSPush(code.Count);
+ }
+
+ /*
+ * Push a destination on the control-flow stack, corresponding to
+ * the next opcode to add.
+ */
+ internal void CSPushDest()
+ {
+ CSPush(-code.Count - 1);
+ }
+
+ /*
+ * Pop an origin from the control-flow stack. An exception is
+ * thrown if the value is not an origin.
+ */
+ internal int CSPopOrig()
+ {
+ int x = CSPop();
+ if (x < 0) {
+ throw new Exception("not an origin");
+ }
+ return x;
+ }
+
+ /*
+ * Pop a destination from the control-flow stack. An exception is
+ * thrown if the value is not a destination.
+ */
+ internal int CSPopDest()
+ {
+ int x = CSPop();
+ if (x >= 0) {
+ throw new Exception("not a destination");
+ }
+ return -x - 1;
+ }
+
+ /*
+ * Add a "push literal" opcode.
+ */
+ internal void Literal(TValue v)
+ {
+ Add(new OpcodeConst(v));
+ }
+
+ /*
+ * Compile a "call" by name. This method implements the support
+ * for local variables:
+ *
+ * - If the target is '>' followed by a local variable name, then
+ * a "put local" opcode is added.
+ *
+ * - Otherwise, if the target is a local variable name, then a
+ * "get local" opcode is added.
+ *
+ * - Otherwise, a call to the named word is added. The target name
+ * will be resolved later on (typically, when the word containing
+ * the call opcode is first invoked, or when C code is generated).
+ */
+ internal void Call(string target)
+ {
+ string lname;
+ bool write;
+ if (target.StartsWith(">")) {
+ lname = target.Substring(1);
+ write = true;
+ } else {
+ lname = target;
+ write = false;
+ }
+ int lnum;
+ if (locals.TryGetValue(lname, out lnum)) {
+ if (write) {
+ Add(new OpcodePutLocal(lnum));
+ } else {
+ Add(new OpcodeGetLocal(lnum));
+ }
+ } else {
+ Add(new OpcodeCall(), target);
+ }
+ }
+
+ /*
+ * Add a "call" opcode to the designated word.
+ */
+ internal void CallExt(Word wtarget)
+ {
+ Add(new OpcodeCall(wtarget), null);
+ }
+
+ /*
+ * Add a "call" opcode to a word which is not currently resolved.
+ * This method ignores local variables.
+ */
+ internal void CallExt(string target)
+ {
+ Add(new OpcodeCall(), target);
+ }
+
+ /*
+ * Add a "get local" opcode; the provided local name must already
+ * be defined.
+ */
+ internal void GetLocal(string name)
+ {
+ int lnum;
+ if (locals.TryGetValue(name, out lnum)) {
+ Add(new OpcodeGetLocal(lnum));
+ } else {
+ throw new Exception("no such local: " + name);
+ }
+ }
+
+ /*
+ * Add a "put local" opcode; the provided local name must already
+ * be defined.
+ */
+ internal void PutLocal(string name)
+ {
+ int lnum;
+ if (locals.TryGetValue(name, out lnum)) {
+ Add(new OpcodePutLocal(lnum));
+ } else {
+ throw new Exception("no such local: " + name);
+ }
+ }
+
+ /*
+ * Define a new local name.
+ */
+ internal void DefLocal(string lname)
+ {
+ if (locals.ContainsKey(lname)) {
+ throw new Exception(String.Format(
+ "local already defined: {0}", lname));
+ }
+ locals[lname] = locals.Count;
+ }
+
+ /*
+ * Add a "call" opcode whose target is an XT value (which may be
+ * resolved or as yet unresolved).
+ */
+ internal void Call(TPointerXT xt)
+ {
+ if (xt.Target == null) {
+ Add(new OpcodeCall(), xt.Name);
+ } else {
+ Add(new OpcodeCall(xt.Target));
+ }
+ }
+
+ /*
+ * Add a "ret" opcode.
+ */
+ internal void Ret()
+ {
+ Add(new OpcodeRet());
+ }
+
+ /*
+ * Add a forward unconditional jump. The new opcode address is
+ * pushed on the control-flow stack as an origin.
+ */
+ internal void Ahead()
+ {
+ CSPushOrig();
+ Add(new OpcodeJumpUncond());
+ }
+
+ /*
+ * Add a forward conditional jump, which will be taken at runtime
+ * if the top-of-stack value is 'true'. The new opcode address is
+ * pushed on the control-flow stack as an origin.
+ */
+ internal void AheadIf()
+ {
+ CSPushOrig();
+ Add(new OpcodeJumpIf());
+ }
+
+ /*
+ * Add a forward conditional jump, which will be taken at runtime
+ * if the top-of-stack value is 'false'. The new opcode address is
+ * pushed on the control-flow stack as an origin.
+ */
+ internal void AheadIfNot()
+ {
+ CSPushOrig();
+ Add(new OpcodeJumpIfNot());
+ }
+
+ /*
+ * Resolve a previous forward jump to the current code address.
+ * The top of control-flow stack is popped and must be an origin.
+ */
+ internal void Then()
+ {
+ int x = CSPopOrig();
+ code[x].ResolveJump(code.Count - x - 1);
+ jumpToLast = true;
+ }
+
+ /*
+ * Push the current code address on the control-flow stack as a
+ * destination, to be used by an ulterior backward jump.
+ */
+ internal void Begin()
+ {
+ CSPushDest();
+ }
+
+ /*
+ * Add a backward unconditional jump. The jump target is popped
+ * from the control-flow stack as a destination.
+ */
+ internal void Again()
+ {
+ int x = CSPopDest();
+ Add(new OpcodeJumpUncond(x - code.Count - 1));
+ }
+
+ /*
+ * Add a backward conditional jump, which will be taken at runtime
+ * if the top-of-stack value is 'true'. The jump target is popped
+ * from the control-flow stack as a destination.
+ */
+ internal void AgainIf()
+ {
+ int x = CSPopDest();
+ Add(new OpcodeJumpIf(x - code.Count - 1));
+ }
+
+ /*
+ * Add a backward conditional jump, which will be taken at runtime
+ * if the top-of-stack value is 'false'. The jump target is popped
+ * from the control-flow stack as a destination.
+ */
+ internal void AgainIfNot()
+ {
+ int x = CSPopDest();
+ Add(new OpcodeJumpIfNot(x - code.Count - 1));
+ }
+}
diff --git a/T0/WordData.cs b/T0/WordData.cs
new file mode 100644
index 000000000000..2d74bd3effe3
--- /dev/null
+++ b/T0/WordData.cs
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+class WordData : Word {
+
+ ConstData blob;
+ string baseBlobName;
+ int offset;
+ bool ongoingResolution;
+
+ internal WordData(T0Comp owner, string name,
+ ConstData blob, int offset)
+ : base(owner, name)
+ {
+ this.blob = blob;
+ this.offset = offset;
+ StackEffect = new SType(0, 1);
+ }
+
+ internal WordData(T0Comp owner, string name,
+ string baseBlobName, int offset)
+ : base(owner, name)
+ {
+ this.baseBlobName = baseBlobName;
+ this.offset = offset;
+ StackEffect = new SType(0, 1);
+ }
+
+ internal override void Resolve()
+ {
+ if (blob != null) {
+ return;
+ }
+ if (ongoingResolution) {
+ throw new Exception(String.Format(
+ "circular reference in blobs ({0})", Name));
+ }
+ ongoingResolution = true;
+ WordData wd = TC.Lookup(baseBlobName) as WordData;
+ if (wd == null) {
+ throw new Exception(String.Format(
+ "data word '{0}' based on non-data word '{1}'",
+ Name, baseBlobName));
+ }
+ wd.Resolve();
+ blob = wd.blob;
+ offset += wd.offset;
+ ongoingResolution = false;
+ }
+
+ internal override void Run(CPU cpu)
+ {
+ Resolve();
+ cpu.Push(new TValue(offset, new TPointerBlob(blob)));
+ }
+
+ internal override List<ConstData> GetDataBlocks()
+ {
+ Resolve();
+ List<ConstData> r = new List<ConstData>();
+ r.Add(blob);
+ return r;
+ }
+
+ internal override void GenerateCodeElements(List<CodeElement> dst)
+ {
+ Resolve();
+ dst.Add(new CodeElementUInt(0));
+ dst.Add(new CodeElementUIntInt(1, blob.Address + offset));
+ dst.Add(new CodeElementUInt(0));
+ }
+}
diff --git a/T0/WordInterpreted.cs b/T0/WordInterpreted.cs
new file mode 100644
index 000000000000..882170b23930
--- /dev/null
+++ b/T0/WordInterpreted.cs
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+/*
+ * The implementation for interpreted words.
+ */
+
+class WordInterpreted : Word {
+
+ /*
+ * Get the number of local variables for this word.
+ */
+ internal int NumLocals {
+ get; private set;
+ }
+
+ /*
+ * Get the sequence of opcodes for this word.
+ */
+ internal Opcode[] Code {
+ get; private set;
+ }
+
+ string[] toResolve;
+
+ internal WordInterpreted(T0Comp owner, string name,
+ int numLocals, Opcode[] code, string[] toResolve)
+ : base(owner, name)
+ {
+ this.Code = code;
+ this.toResolve = toResolve;
+ NumLocals = numLocals;
+ }
+
+ internal override void Resolve()
+ {
+ if (toResolve == null) {
+ return;
+ }
+ for (int i = 0; i < toResolve.Length; i ++) {
+ string tt = toResolve[i];
+ if (tt == null) {
+ continue;
+ }
+ Code[i].ResolveTarget(TC.Lookup(tt));
+ }
+ toResolve = null;
+ }
+
+ internal override void Run(CPU cpu)
+ {
+ Resolve();
+ cpu.Enter(Code, NumLocals);
+ }
+
+ internal override List<Word> GetReferences()
+ {
+ Resolve();
+ List<Word> r = new List<Word>();
+ foreach (Opcode op in Code) {
+ Word w = op.GetReference(TC);
+ if (w != null) {
+ r.Add(w);
+ }
+ }
+ return r;
+ }
+
+ internal override List<ConstData> GetDataBlocks()
+ {
+ Resolve();
+ List<ConstData> r = new List<ConstData>();
+ foreach (Opcode op in Code) {
+ ConstData cd = op.GetDataBlock(TC);
+ if (cd != null) {
+ r.Add(cd);
+ }
+ }
+ return r;
+ }
+
+ internal override void GenerateCodeElements(List<CodeElement> dst)
+ {
+ Resolve();
+ int n = Code.Length;
+ CodeElement[] gcode = new CodeElement[n];
+ for (int i = 0; i < n; i ++) {
+ gcode[i] = Code[i].ToCodeElement();
+ }
+ for (int i = 0; i < n; i ++) {
+ Code[i].FixUp(gcode, i);
+ }
+ dst.Add(new CodeElementUInt((uint)NumLocals));
+ for (int i = 0; i < n; i ++) {
+ dst.Add(gcode[i]);
+ }
+ }
+
+ int flowAnalysis;
+ int maxDataStack;
+ int maxReturnStack;
+
+ bool MergeSA(int[] sa, int j, int c)
+ {
+ if (sa[j] == Int32.MinValue) {
+ sa[j] = c;
+ return true;
+ } else if (sa[j] != c) {
+ throw new Exception(string.Format(
+ "In word '{0}', offset {1}:"
+ + " stack action mismatch ({2} / {3})",
+ Name, j, sa[j], c));
+ } else {
+ return false;
+ }
+ }
+
+ internal override void AnalyseFlow()
+ {
+ switch (flowAnalysis) {
+ case 0:
+ break;
+ case 1:
+ return;
+ default:
+ throw new Exception("recursive call detected in '"
+ + Name + "'");
+ }
+ flowAnalysis = 2;
+ int n = Code.Length;
+ int[] sa = new int[n];
+ for (int i = 0; i < n; i ++) {
+ sa[i] = Int32.MinValue;
+ }
+ sa[0] = 0;
+ int[] toExplore = new int[n];
+ int tX = 0, tY = 0;
+ int off = 0;
+
+ int exitSA = Int32.MinValue;
+ int mds = 0;
+ int mrs = 0;
+
+ int maxDepth = 0;
+
+ for (;;) {
+ Opcode op = Code[off];
+ bool mft = op.MayFallThrough;
+ int c = sa[off];
+ int a;
+ if (op is OpcodeCall) {
+ Word w = op.GetReference(TC);
+ w.AnalyseFlow();
+ SType se = w.StackEffect;
+ if (!se.IsKnown) {
+ throw new Exception(string.Format(
+ "call from '{0}' to '{1}'"
+ + " with unknown stack effect",
+ Name, w.Name));
+ }
+ if (se.NoExit) {
+ mft = false;
+ a = 0;
+ } else {
+ a = se.DataOut - se.DataIn;
+ }
+ mds = Math.Max(mds, c + w.MaxDataStack);
+ mrs = Math.Max(mrs, w.MaxReturnStack);
+ maxDepth = Math.Min(maxDepth, c - se.DataIn);
+ } else if (op is OpcodeRet) {
+ if (exitSA == Int32.MinValue) {
+ exitSA = c;
+ } else if (exitSA != c) {
+ throw new Exception(string.Format(
+ "'{0}': exit stack action"
+ + " mismatch: {1} / {2}"
+ + " (offset {3})",
+ Name, exitSA, c, off));
+ }
+ a = 0;
+ } else {
+ a = op.StackAction;
+ mds = Math.Max(mds, c + a);
+ }
+ c += a;
+ maxDepth = Math.Min(maxDepth, c);
+
+ int j = op.JumpDisp;
+ if (j != 0) {
+ j += off + 1;
+ toExplore[tY ++] = j;
+ MergeSA(sa, j, c);
+ }
+ off ++;
+ if (!mft || !MergeSA(sa, off, c)) {
+ if (tX < tY) {
+ off = toExplore[tX ++];
+ } else {
+ break;
+ }
+ }
+ }
+
+ maxDataStack = mds;
+ maxReturnStack = 1 + NumLocals + mrs;
+
+ /*
+ * TODO: see about this warning. Usage of a 'fail'
+ * word (that does not exit) within a 'case..endcase'
+ * structure will make an unreachable opcode. In a future
+ * version we might want to automatically remove dead
+ * opcodes.
+ for (int i = 0; i < n; i ++) {
+ if (sa[i] == Int32.MinValue) {
+ Console.WriteLine("warning: word '{0}',"
+ + " offset {1}: unreachable opcode",
+ Name, i);
+ continue;
+ }
+ }
+ */
+
+ SType computed;
+ if (exitSA == Int32.MinValue) {
+ computed = new SType(-maxDepth, -1);
+ } else {
+ computed = new SType(-maxDepth, -maxDepth + exitSA);
+ }
+
+ if (StackEffect.IsKnown) {
+ if (!computed.IsSubOf(StackEffect)) {
+ throw new Exception(string.Format(
+ "word '{0}':"
+ + " computed stack effect {1}"
+ + " does not match declared {2}",
+ Name, computed.ToString(),
+ StackEffect.ToString()));
+ }
+ } else {
+ StackEffect = computed;
+ }
+
+ flowAnalysis = 1;
+ }
+
+ internal override int MaxDataStack {
+ get {
+ AnalyseFlow();
+ return maxDataStack;
+ }
+ }
+
+ internal override int MaxReturnStack {
+ get {
+ AnalyseFlow();
+ return maxReturnStack;
+ }
+ }
+}
diff --git a/T0/WordNative.cs b/T0/WordNative.cs
new file mode 100644
index 000000000000..786887253762
--- /dev/null
+++ b/T0/WordNative.cs
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+
+/*
+ * Class for native words.
+ */
+
+class WordNative : Word {
+
+ /*
+ * A type for the native implementation: a method that takes a
+ * CPU as parameter, and returns nothing.
+ */
+ internal delegate void NativeRun(CPU cpu);
+
+ NativeRun code;
+
+ internal WordNative(T0Comp owner, string name, NativeRun code)
+ : base(owner, name)
+ {
+ this.code = code;
+ }
+
+ internal WordNative(T0Comp owner, string name,
+ SType stackEffect, NativeRun code)
+ : this(owner, name, code)
+ {
+ StackEffect = stackEffect;
+ }
+
+ internal override void Run(CPU cpu)
+ {
+ code(cpu);
+ }
+}
diff --git a/T0/kern.t0 b/T0/kern.t0
new file mode 100644
index 000000000000..9fce4f84d301
--- /dev/null
+++ b/T0/kern.t0
@@ -0,0 +1,309 @@
+: \ `\n parse drop ; immediate
+
+\ This file defines the core non-native functions (mainly used for
+\ parsing words, i.e. not part of the generated output). The line above
+\ defines the syntax for comments.
+
+\ Define parenthesis comments.
+\ : ( `) parse drop ; immediate
+
+: else postpone ahead 1 cs-roll postpone then ; immediate
+: while postpone if 1 cs-roll ; immediate
+: repeat postpone again postpone then ; immediate
+
+: ['] ' ; immediate
+: [compile] compile ; immediate
+
+: 2drop drop drop ;
+: dup2 over over ;
+
+\ Local variables are defined with the native word '(local)'. We define
+\ a helper construction that mimics what is found in Apple's Open Firmware
+\ implementation. The syntax is: { a b ... ; c d ... }
+\ I.e. there is an opening brace, then some names. Names appearing before
+\ the semicolon are locals that are both defined and then filled with the
+\ values on stack (in stack order: { a b } fills 'b' with the top-of-stack,
+\ and 'a' with the value immediately below). Names appearing after the
+\ semicolon are not initialized.
+: __deflocal ( from_stack name -- )
+ dup (local) swap if
+ compile-local-write
+ else
+ drop
+ then ;
+: __deflocals ( from_stack -- )
+ next-word
+ dup "}" eqstr if
+ 2drop ret
+ then
+ dup ";" eqstr if
+ 2drop 0 __deflocals ret
+ then
+ over __deflocals
+ __deflocal ;
+: {
+ -1 __deflocals ; immediate
+
+\ Data building words.
+: data:
+ new-data-block next-word define-data-word ;
+: hexb|
+ 0 0 { acc z }
+ begin
+ char
+ dup `| = if
+ z if "Truncated hexadecimal byte" puts cr exitvm then
+ ret
+ then
+ dup 0x20 > if
+ hexval
+ z if acc 4 << + data-add8 else >acc then
+ z not >z
+ then
+ again ;
+
+\ Convert hexadecimal character to number. Complain loudly if conversion
+\ is not possible.
+: hexval ( char -- x )
+ hexval-nf dup 0 < if "Not an hex digit: " puts . cr exitvm then ;
+
+\ Convert hexadecimal character to number. If not an hexadecimal digit,
+\ return -1.
+: hexval-nf ( char -- x )
+ dup dup `0 >= swap `9 <= and if `0 - ret then
+ dup dup `A >= swap `F <= and if `A - 10 + ret then
+ dup dup `a >= swap `f <= and if `a - 10 + ret then
+ drop -1 ;
+
+\ Convert decimal character to number. Complain loudly if conversion
+\ is not possible.
+: decval ( char -- x )
+ decval-nf dup 0 < if "Not a decimal digit: " puts . cr exitvm then ;
+
+\ Convert decimal character to number. If not a decimal digit,
+\ return -1.
+: decval-nf ( char -- x )
+ dup dup `0 >= swap `9 <= and if `0 - ret then
+ drop -1 ;
+
+\ Commonly used shorthands.
+: 1+ 1 + ;
+: 2+ 2 + ;
+: 1- 1 - ;
+: 2- 2 - ;
+: 0= 0 = ;
+: 0<> 0 <> ;
+: 0< 0 < ;
+: 0> 0 > ;
+
+\ Get a 16-bit value from the constant data block. This uses big-endian
+\ encoding.
+: data-get16 ( addr -- x )
+ dup data-get8 8 << swap 1+ data-get8 + ;
+
+\ The case..endcase construction is the equivalent of 'switch' is C.
+\ Usage:
+\ case
+\ E1 of C1 endof
+\ E2 of C2 endof
+\ ...
+\ CN
+\ endcase
+\
+\ Upon entry, it considers the TOS (let's call it X). It will then evaluate
+\ E1, which should yield a single value Y1; at that point, the X value is
+\ still on the stack, just below Y1, and must remain untouched. The 'of'
+\ word compares X with Y1; if they are equal, C1 is executed, and then
+\ control jumps to after the 'endcase'. The X value is popped from the
+\ stack immediately before evaluating C1.
+\
+\ If X and Y1 are not equal, flow proceeds to E2, to obtain a value Y2 to
+\ compare with X. And so on.
+\
+\ If none of the 'of' clauses found a match, then CN is evaluated. When CN
+\ is evaluated, the X value is on the TOS, and CN must either leave it on
+\ the stack, or replace it with exactly one value; the 'endcase' word
+\ expects (and drops) one value.
+\
+\ Implementation: this is mostly copied from ANS Forth specification,
+\ although simplified a bit because we know that our control-flow stack
+\ is independent of the data stack. During compilation, the number of
+\ clauses is maintained on the stack; each of..endof clause really is
+\ an 'if..else' that must be terminated with a matching 'then' in 'endcase'.
+
+: case 0 ; immediate
+: of 1+ postpone over postpone = postpone if postpone drop ; immediate
+: endof postpone else ; immediate
+: endcase
+ postpone drop
+ begin dup while 1- postpone then repeat drop ; immediate
+
+\ A simpler and more generic "case": there is no management for a value
+\ on the stack, and each test is supposed to come up with its own boolean
+\ value.
+: choice 0 ; immediate
+: uf 1+ postpone if ; immediate
+: ufnot 1+ postpone ifnot ; immediate
+: enduf postpone else ; immediate
+: endchoice begin dup while 1- postpone then repeat drop ; immediate
+
+\ C implementations for native words that can be used in generated code.
+add-cc: co { T0_CO(); }
+add-cc: execute { T0_ENTER(ip, rp, T0_POP()); }
+add-cc: drop { (void)T0_POP(); }
+add-cc: dup { T0_PUSH(T0_PEEK(0)); }
+add-cc: swap { T0_SWAP(); }
+add-cc: over { T0_PUSH(T0_PEEK(1)); }
+add-cc: rot { T0_ROT(); }
+add-cc: -rot { T0_NROT(); }
+add-cc: roll { T0_ROLL(T0_POP()); }
+add-cc: pick { T0_PICK(T0_POP()); }
+add-cc: + {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a + b);
+}
+add-cc: - {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a - b);
+}
+add-cc: neg {
+ uint32_t a = T0_POP();
+ T0_PUSH(-a);
+}
+add-cc: * {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a * b);
+}
+add-cc: / {
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSHi(a / b);
+}
+add-cc: u/ {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a / b);
+}
+add-cc: % {
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSHi(a % b);
+}
+add-cc: u% {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a % b);
+}
+add-cc: < {
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a < b));
+}
+add-cc: <= {
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a <= b));
+}
+add-cc: > {
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a > b));
+}
+add-cc: >= {
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a >= b));
+}
+add-cc: = {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a == b));
+}
+add-cc: <> {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a != b));
+}
+add-cc: u< {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a < b));
+}
+add-cc: u<= {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a <= b));
+}
+add-cc: u> {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a > b));
+}
+add-cc: u>= {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a >= b));
+}
+add-cc: and {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a & b);
+}
+add-cc: or {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a | b);
+}
+add-cc: xor {
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a ^ b);
+}
+add-cc: not {
+ uint32_t a = T0_POP();
+ T0_PUSH(~a);
+}
+add-cc: << {
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x << c);
+}
+add-cc: >> {
+ int c = (int)T0_POPi();
+ int32_t x = T0_POPi();
+ T0_PUSHi(x >> c);
+}
+add-cc: u>> {
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x >> c);
+}
+add-cc: data-get8 {
+ size_t addr = T0_POP();
+ T0_PUSH(t0_datablock[addr]);
+}
+
+add-cc: . {
+ extern int printf(const char *fmt, ...);
+ printf(" %ld", (long)T0_POPi());
+}
+add-cc: putc {
+ extern int printf(const char *fmt, ...);
+ printf("%c", (char)T0_POPi());
+}
+add-cc: puts {
+ extern int printf(const char *fmt, ...);
+ printf("%s", &t0_datablock[T0_POPi()]);
+}
+add-cc: cr {
+ extern int printf(const char *fmt, ...);
+ printf("\n");
+}
+add-cc: eqstr {
+ const void *b = &t0_datablock[T0_POPi()];
+ const void *a = &t0_datablock[T0_POPi()];
+ T0_PUSH(-(int32_t)(strcmp(a, b) == 0));
+}
diff --git a/T0Comp.exe b/T0Comp.exe
new file mode 100755
index 000000000000..67eba109800e
--- /dev/null
+++ b/T0Comp.exe
Binary files differ
diff --git a/build/.do_not_remove b/build/.do_not_remove
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/build/.do_not_remove
diff --git a/conf/Unix.mk b/conf/Unix.mk
new file mode 100644
index 000000000000..02f2b2be8ee4
--- /dev/null
+++ b/conf/Unix.mk
@@ -0,0 +1,69 @@
+# Configuration for a native build on a generic Unix-like system.
+
+# Build directory.
+BUILD = build
+
+# Extension for executable files.
+E =
+
+# Extension for object files.
+O = .o
+
+# Prefix for library file name.
+LP = lib
+
+# Extension for library file name.
+L = .a
+
+# Prefix for DLL file name.
+DP = lib
+
+# Extension for DLL file name.
+D = .so
+
+# Output file names can be overridden directly. By default, they are
+# assembled using the prefix/extension macros defined above.
+# BEARSSLLIB = libbearssl.a
+# BEARSSLDLL = libbearssl.so
+# BRSSL = brssl
+# TESTCRYPTO = testcrypto
+# TESTSPEED = testspeed
+# TESTX509 = testx509
+
+# File deletion tool.
+RM = rm -f
+
+# Directory creation tool.
+MKDIR = mkdir -p
+
+# C compiler and flags.
+CC = cc
+CFLAGS = -W -Wall -Os -fPIC
+CCOUT = -c -o
+
+# Static library building tool.
+AR = ar
+ARFLAGS = -rcs
+AROUT =
+
+# DLL building tool.
+LDDLL = cc
+LDDLLFLAGS = -shared
+LDDLLOUT = -o
+
+# Static linker.
+LD = cc
+LDFLAGS =
+LDOUT = -o
+
+# C# compiler; we assume usage of Mono.
+MKT0COMP = mk$PmkT0.sh
+RUNT0COMP = mono T0Comp.exe
+
+# Set the values to 'no' to disable building of the corresponding element
+# by default. Building can still be invoked with an explicit target call
+# (e.g. 'make dll' to force build the DLL).
+#STATICLIB = no
+#DLL = no
+#TOOLS = no
+#TESTS = no
diff --git a/conf/Unix32.mk b/conf/Unix32.mk
new file mode 100644
index 000000000000..0d3bed8808b5
--- /dev/null
+++ b/conf/Unix32.mk
@@ -0,0 +1,12 @@
+# Example configuration file for compiling on a Unix-like system with
+# GCC, targeting a 32-bit output. Moreover, it enables the "LOMUL" setting
+# to make the code select the "small" integer implementations (i15, m15,
+# ctmul32...), which is not necessarily a good idea for performance, but
+# handy for tests.
+
+include conf/Unix.mk
+
+BUILD = build32
+CFLAGS = -W -Wall -Os -fPIC -m32 -DBR_LOMUL
+LDFLAGS = -m32
+LDDLLFLAGS = -shared -m32
diff --git a/conf/UnixClang.mk b/conf/UnixClang.mk
new file mode 100644
index 000000000000..3636cf896c78
--- /dev/null
+++ b/conf/UnixClang.mk
@@ -0,0 +1,11 @@
+# Example configuration file for compiling on a Unix-like system with
+# clang as compiler instead of gcc.
+
+# We are on a Unix system so we assume a Single Unix compatible 'make'
+# utility, and Unix defaults.
+include conf/Unix.mk
+
+BUILD = bclang
+CC = clang
+LD = clang
+LDDLL = clang
diff --git a/conf/Win.mk b/conf/Win.mk
new file mode 100644
index 000000000000..2ed4bb6895aa
--- /dev/null
+++ b/conf/Win.mk
@@ -0,0 +1,70 @@
+# Configuration for a native build on a Windows system with Visual Studio.
+
+# Build directory.
+BUILD = build
+
+# Extension for executable files.
+E = .exe
+
+# Extension for object files.
+O = .obj
+
+# Prefix for static library file name.
+LP =
+
+# Extension for static library file name. We add an 's' so that the
+# name is distinct from the 'import library' generated along with the DLL.
+L = s.lib
+
+# Prefix for DLL file name.
+DP =
+
+# Extension for DLL file name.
+D = .dll
+
+# Output file names can be overridden directly. By default, they are
+# assembled using the prefix/extension macros defined above.
+# BEARSSLLIB = bearssls.lib
+# BEARSSLDLL = bearssl.dll
+# BRSSL = brssl.exe
+# TESTCRYPTO = testcrypto.exe
+# TESTSPEED = testspeed.exe
+# TESTX509 = testx509.exe
+
+# File deletion tool.
+RM = del /Q
+
+# Directory creation tool.
+MKDIR = mkdir
+
+# C compiler and flags.
+CC = cl
+CFLAGS = -nologo -W2 -O2
+CCOUT = -c -Fo
+
+# Static library building tool.
+AR = lib
+ARFLAGS = -nologo
+AROUT = -out:
+
+# DLL building tool.
+LDDLL = cl
+LDDLLFLAGS = -nologo -LD -MT
+LDDLLOUT = -Fe
+
+# Static linker.
+LD = cl
+LDFLAGS = -nologo
+LDOUT = -Fe
+
+# C# compiler.
+MKT0COMP = mk$PmkT0.cmd
+RUNT0COMP = T0Comp.exe
+
+# Set the values to 'no' to disable building of the corresponding element
+# by default. Building can still be invoked with an explicit target call
+# (e.g. 'make dll' to force build the DLL).
+#STATICLIB = no
+#DLL = no
+#TOOLS = no
+#TESTS = no
diff --git a/conf/samd20.mk b/conf/samd20.mk
new file mode 100644
index 000000000000..5b3d5004c38a
--- /dev/null
+++ b/conf/samd20.mk
@@ -0,0 +1,20 @@
+# Example configuration file for compiling for an Atmel SAM D20 Xplained
+# Pro evaluation kit, on a Unix-like system, with a GNU toolchain.
+
+# We are on a Unix system so we assume a Single Unix compatible 'make'
+# utility, and Unix defaults.
+include conf/Unix.mk
+
+# We override the build directory.
+BUILD = samd20
+
+# C compiler, linker, and static library builder.
+CC = arm-none-eabi-gcc
+CFLAGS = -W -Wall -Os -mthumb -ffunction-sections -fdata-sections -mcpu=cortex-m0plus -DBR_ARMEL_CORTEXM_GCC
+LD = arm-none-eabi-gcc
+AR = arm-none-eabi-ar
+
+# We compile only the static library.
+DLL = no
+TOOLS = no
+TESTS = no
diff --git a/inc/bearssl.h b/inc/bearssl.h
new file mode 100644
index 000000000000..4f4797cf7937
--- /dev/null
+++ b/inc/bearssl.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef BR_BEARSSL_H__
+#define BR_BEARSSL_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+/** \mainpage BearSSL API
+ *
+ * # API Layout
+ *
+ * The functions and structures defined by the BearSSL API are located
+ * in various header files:
+ *
+ * | Header file | Elements |
+ * | :-------------- | :------------------------------------------------ |
+ * | bearssl_hash.h | Hash functions |
+ * | bearssl_hmac.h | HMAC |
+ * | bearssl_kdf.h | Key Derivation Functions |
+ * | bearssl_rand.h | Pseudorandom byte generators |
+ * | bearssl_prf.h | PRF implementations (for SSL/TLS) |
+ * | bearssl_block.h | Symmetric encryption |
+ * | bearssl_aead.h | AEAD algorithms (combined encryption + MAC) |
+ * | bearssl_rsa.h | RSA encryption and signatures |
+ * | bearssl_ec.h | Elliptic curves support (including ECDSA) |
+ * | bearssl_ssl.h | SSL/TLS engine interface |
+ * | bearssl_x509.h | X.509 certificate decoding and validation |
+ * | bearssl_pem.h | Base64/PEM decoding support functions |
+ *
+ * Applications using BearSSL are supposed to simply include `bearssl.h`
+ * as follows:
+ *
+ * #include <bearssl.h>
+ *
+ * The `bearssl.h` file itself includes all the other header files. It is
+ * possible to include specific header files, but it has no practical
+ * advantage for the application. The API is separated into separate
+ * header files only for documentation convenience.
+ *
+ *
+ * # Conventions
+ *
+ * ## MUST and SHALL
+ *
+ * In all descriptions, the usual "MUST", "SHALL", "MAY",... terminology
+ * is used. Failure to meet requirements expressed with a "MUST" or
+ * "SHALL" implies undefined behaviour, which means that segmentation
+ * faults, buffer overflows, and other similar adverse events, may occur.
+ *
+ * In general, BearSSL is not very forgiving of programming errors, and
+ * does not include much failsafes or error reporting when the problem
+ * does not arise from external transient conditions, and can be fixed
+ * only in the application code. This is done so in order to make the
+ * total code footprint lighter.
+ *
+ *
+ * ## `NULL` values
+ *
+ * Function parameters with a pointer type shall not be `NULL` unless
+ * explicitly authorised by the documentation. As an exception, when
+ * the pointer aims at a sequence of bytes and is accompanied with
+ * a length parameter, and the length is zero (meaning that there is
+ * no byte at all to retrieve), then the pointer may be `NULL` even if
+ * not explicitly allowed.
+ *
+ *
+ * ## Memory Allocation
+ *
+ * BearSSL does not perform dynamic memory allocation. This implies that
+ * for any functionality that requires a non-transient state, the caller
+ * is responsible for allocating the relevant context structure. Such
+ * allocation can be done in any appropriate area, including static data
+ * segments, the heap, and the stack, provided that proper alignment is
+ * respected. The header files define these context structures
+ * (including size and contents), so the C compiler should handle
+ * alignment automatically.
+ *
+ * Since there is no dynamic resource allocation, there is also nothing to
+ * release. When the calling code is done with a BearSSL feature, it
+ * may simple release the context structures it allocated itself, with
+ * no "close function" to call. If the context structures were allocated
+ * on the stack (as local variables), then even that release operation is
+ * implicit.
+ *
+ *
+ * ## Structure Contents
+ *
+ * Except when explicitly indicated, structure contents are opaque: they
+ * are included in the header files so that calling code may know the
+ * structure sizes and alignment requirements, but callers SHALL NOT
+ * access individual fields directly. For fields that are supposed to
+ * be read from or written to, the API defines accessor functions (the
+ * simplest of these accessor functions are defined as `static inline`
+ * functions, and the C compiler will optimise them away).
+ *
+ *
+ * # API Usage
+ *
+ * BearSSL usage for running a SSL/TLS client or server is described
+ * on the [BearSSL Web site](https://www.bearssl.org/api1.html). The
+ * BearSSL source archive also comes with sample code.
+ */
+
+#include "bearssl_hash.h"
+#include "bearssl_hmac.h"
+#include "bearssl_kdf.h"
+#include "bearssl_rand.h"
+#include "bearssl_prf.h"
+#include "bearssl_block.h"
+#include "bearssl_aead.h"
+#include "bearssl_rsa.h"
+#include "bearssl_ec.h"
+#include "bearssl_ssl.h"
+#include "bearssl_x509.h"
+#include "bearssl_pem.h"
+
+/** \brief Type for a configuration option.
+ *
+ * A "configuration option" is a value that is selected when the BearSSL
+ * library itself is compiled. Most options are boolean; their value is
+ * then either 1 (option is enabled) or 0 (option is disabled). Some
+ * values have other integer values. Option names correspond to macro
+ * names. Some of the options can be explicitly set in the internal
+ * `"config.h"` file.
+ */
+typedef struct {
+ /** \brief Configurable option name. */
+ const char *name;
+ /** \brief Configurable option value. */
+ long value;
+} br_config_option;
+
+/** \brief Get configuration report.
+ *
+ * This function returns compiled configuration options, each as a
+ * 'long' value. Names match internal macro names, in particular those
+ * that can be set in the `"config.h"` inner file. For boolean options,
+ * the numerical value is 1 if enabled, 0 if disabled. For maximum
+ * key sizes, values are expressed in bits.
+ *
+ * The returned array is terminated by an entry whose `name` is `NULL`.
+ *
+ * \return the configuration report.
+ */
+const br_config_option *br_get_config(void);
+
+#endif
diff --git a/inc/bearssl_aead.h b/inc/bearssl_aead.h
new file mode 100644
index 000000000000..8e35a1fdeb43
--- /dev/null
+++ b/inc/bearssl_aead.h
@@ -0,0 +1,1059 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef BR_BEARSSL_AEAD_H__
+#define BR_BEARSSL_AEAD_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "bearssl_block.h"
+#include "bearssl_hash.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file bearssl_aead.h
+ *
+ * # Authenticated Encryption with Additional Data
+ *
+ * This file documents the API for AEAD encryption.
+ *
+ *
+ * ## Procedural API
+ *
+ * An AEAD algorithm processes messages and provides confidentiality
+ * (encryption) and checked integrity (MAC). It uses the following
+ * parameters:
+ *
+ * - A symmetric key. Exact size depends on the AEAD algorithm.
+ *
+ * - A nonce (IV). Size depends on the AEAD algorithm; for most
+ * algorithms, it is crucial for security that any given nonce
+ * value is never used twice for the same key and distinct
+ * messages.
+ *
+ * - Data to encrypt and protect.
+ *
+ * - Additional authenticated data, which is covered by the MAC but
+ * otherwise left untouched (i.e. not encrypted).
+ *
+ * The AEAD algorithm encrypts the data, and produces an authentication
+ * tag. It is assumed that the encrypted data, the tag, the additional
+ * authenticated data and the nonce are sent to the receiver; the
+ * additional data and the nonce may be implicit (e.g. using elements of
+ * the underlying transport protocol, such as record sequence numbers).
+ * The receiver will recompute the tag value and compare it with the one
+ * received; if they match, then the data is correct, and can be
+ * decrypted and used; otherwise, at least one of the elements was
+ * altered in transit, normally leading to wholesale rejection of the
+ * complete message.
+ *
+ * For each AEAD algorithm, identified by a symbolic name (hereafter
+ * denoted as "`xxx`"), the following functions are defined:
+ *
+ * - `br_xxx_init()`
+ *
+ * Initialise the AEAD algorithm, on a provided context structure.
+ * Exact parameters depend on the algorithm, and may include
+ * pointers to extra implementations and context structures. The
+ * secret key is provided at this point, either directly or
+ * indirectly.
+ *
+ * - `br_xxx_reset()`
+ *
+ * Start a new AEAD computation. The nonce value is provided as
+ * parameter to this function.
+ *
+ * - `br_xxx_aad_inject()`
+ *
+ * Inject some additional authenticated data. Additional data may
+ * be provided in several chunks of arbitrary length.
+ *
+ * - `br_xxx_flip()`
+ *
+ * This function MUST be called after injecting all additional
+ * authenticated data, and before beginning to encrypt the plaintext
+ * (or decrypt the ciphertext).
+ *
+ * - `br_xxx_run()`
+ *
+ * Process some plaintext (to encrypt) or ciphertext (to decrypt).
+ * Encryption/decryption is done in place. Data may be provided in
+ * several chunks of arbitrary length.
+ *
+ * - `br_xxx_get_tag()`
+ *
+ * Compute the authentication tag. All message data (encrypted or
+ * decrypted) must have been injected at that point. Also, this
+ * call may modify internal context elements, so it may be called
+ * only once for a given AEAD computation.
+ *
+ * - `br_xxx_check_tag()`
+ *
+ * An alternative to `br_xxx_get_tag()`, meant to be used by the
+ * receiver: the authentication tag is internally recomputed, and
+ * compared with the one provided as parameter.
+ *
+ * This API makes the following assumptions on the AEAD algorithm:
+ *
+ * - Encryption does not expand the size of the ciphertext; there is
+ * no padding. This is true of most modern AEAD modes such as GCM.
+ *
+ * - The additional authenticated data must be processed first,
+ * before the encrypted/decrypted data.
+ *
+ * - Nonce, plaintext and additional authenticated data all consist
+ * in an integral number of bytes. There is no provision to use
+ * elements whose length in bits is not a multiple of 8.
+ *
+ * Each AEAD algorithm has its own requirements and limits on the sizes
+ * of additional data and plaintext. This API does not provide any
+ * way to report invalid usage; it is up to the caller to ensure that
+ * the provided key, nonce, and data elements all fit the algorithm's
+ * requirements.
+ *
+ *
+ * ## Object-Oriented API
+ *
+ * Each context structure begins with a field (called `vtable`) that
+ * points to an instance of a structure that references the relevant
+ * functions through pointers. Each such structure contains the
+ * following:
+ *
+ * - `reset`
+ *
+ * Pointer to the reset function, that allows starting a new
+ * computation.
+ *
+ * - `aad_inject`
+ *
+ * Pointer to the additional authenticated data injection function.
+ *
+ * - `flip`
+ *
+ * Pointer to the function that transitions from additional data
+ * to main message data processing.
+ *
+ * - `get_tag`
+ *
+ * Pointer to the function that computes and returns the tag.
+ *
+ * - `check_tag`
+ *
+ * Pointer to the function that computes and verifies the tag against
+ * a received value.
+ *
+ * Note that there is no OOP method for context initialisation: the
+ * various AEAD algorithms have different requirements that would not
+ * map well to a single initialisation API.
+ *
+ * The OOP API is not provided for CCM, due to its specific requirements
+ * (length of plaintext must be known in advance).
+ */
+
+/**
+ * \brief Class type of an AEAD algorithm.
+ */
+typedef struct br_aead_class_ br_aead_class;
+struct br_aead_class_ {
+
+ /**
+ * \brief Size (in bytes) of authentication tags created by
+ * this AEAD algorithm.
+ */
+ size_t tag_size;
+
+ /**
+ * \brief Reset an AEAD context.
+ *
+ * This function resets an already initialised AEAD context for
+ * a new computation run. Implementations and keys are
+ * conserved. This function can be called at any time; it
+ * cancels any ongoing AEAD computation that uses the provided
+ * context structure.
+
+ * The provided IV is a _nonce_. Each AEAD algorithm has its
+ * own requirements on IV size and contents; for most of them,
+ * it is crucial to security that each nonce value is used
+ * only once for a given secret key.
+ *
+ * \param cc AEAD context structure.
+ * \param iv AEAD nonce to use.
+ * \param len AEAD nonce length (in bytes).
+ */
+ void (*reset)(const br_aead_class **cc, const void *iv, size_t len);
+
+ /**
+ * \brief Inject additional authenticated data.
+ *
+ * The provided data is injected into a running AEAD
+ * computation. Additional data must be injected _before_ the
+ * call to `flip()`. Additional data can be injected in several
+ * chunks of arbitrary length.
+ *
+ * \param cc AEAD context structure.
+ * \param data pointer to additional authenticated data.
+ * \param len length of additional authenticated data (in bytes).
+ */
+ void (*aad_inject)(const br_aead_class **cc,
+ const void *data, size_t len);
+
+ /**
+ * \brief Finish injection of additional authenticated data.
+ *
+ * This function MUST be called before beginning the actual
+ * encryption or decryption (with `run()`), even if no
+ * additional authenticated data was injected. No additional
+ * authenticated data may be injected after this function call.
+ *
+ * \param cc AEAD context structure.
+ */
+ void (*flip)(const br_aead_class **cc);
+
+ /**
+ * \brief Encrypt or decrypt some data.
+ *
+ * Data encryption or decryption can be done after `flip()` has
+ * been called on the context. If `encrypt` is non-zero, then
+ * the provided data shall be plaintext, and it is encrypted in
+ * place. Otherwise, the data shall be ciphertext, and it is
+ * decrypted in place.
+ *
+ * Data may be provided in several chunks of arbitrary length.
+ *
+ * \param cc AEAD context structure.
+ * \param encrypt non-zero for encryption, zero for decryption.
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ */
+ void (*run)(const br_aead_class **cc, int encrypt,
+ void *data, size_t len);
+
+ /**
+ * \brief Compute authentication tag.
+ *
+ * Compute the AEAD authentication tag. The tag length depends
+ * on the AEAD algorithm; it is written in the provided `tag`
+ * buffer. This call terminates the AEAD run: no data may be
+ * processed with that AEAD context afterwards, until `reset()`
+ * is called to initiate a new AEAD run.
+ *
+ * The tag value must normally be sent along with the encrypted
+ * data. When decrypting, the tag value must be recomputed and
+ * compared with the received tag: if the two tag values differ,
+ * then either the tag or the encrypted data was altered in
+ * transit. As an alternative to this function, the
+ * `check_tag()` function may be used to compute and check the
+ * tag value.
+ *
+ * Tag length depends on the AEAD algorithm.
+ *
+ * \param cc AEAD context structure.
+ * \param tag destination buffer for the tag.
+ */
+ void (*get_tag)(const br_aead_class **cc, void *tag);
+
+ /**
+ * \brief Compute and check authentication tag.
+ *
+ * This function is an alternative to `get_tag()`, and is
+ * normally used on the receiving end (i.e. when decrypting
+ * messages). The tag value is recomputed and compared with the
+ * provided tag value. If they match, 1 is returned; on
+ * mismatch, 0 is returned. A returned value of 0 means that the
+ * data or the tag was altered in transit, normally leading to
+ * wholesale rejection of the complete message.
+ *
+ * Tag length depends on the AEAD algorithm.
+ *
+ * \param cc AEAD context structure.
+ * \param tag tag value to compare with.
+ * \return 1 on success (exact match of tag value), 0 otherwise.
+ */
+ uint32_t (*check_tag)(const br_aead_class **cc, const void *tag);
+
+ /**
+ * \brief Compute authentication tag (with truncation).
+ *
+ * This function is similar to `get_tag()`, except that the tag
+ * length is provided. Some AEAD algorithms allow several tag
+ * lengths, usually by truncating the normal tag. Shorter tags
+ * mechanically increase success probability of forgeries.
+ * The range of allowed tag lengths depends on the algorithm.
+ *
+ * \param cc AEAD context structure.
+ * \param tag destination buffer for the tag.
+ * \param len tag length (in bytes).
+ */
+ void (*get_tag_trunc)(const br_aead_class **cc, void *tag, size_t len);
+
+ /**
+ * \brief Compute and check authentication tag (with truncation).
+ *
+ * This function is similar to `check_tag()` except that it
+ * works over an explicit tag length. See `get_tag()` for a
+ * discussion of explicit tag lengths; the range of allowed tag
+ * lengths depends on the algorithm.
+ *
+ * \param cc AEAD context structure.
+ * \param tag tag value to compare with.
+ * \param len tag length (in bytes).
+ * \return 1 on success (exact match of tag value), 0 otherwise.
+ */
+ uint32_t (*check_tag_trunc)(const br_aead_class **cc,
+ const void *tag, size_t len);
+};
+
+/**
+ * \brief Context structure for GCM.
+ *
+ * GCM is an AEAD mode that combines a block cipher in CTR mode with a
+ * MAC based on GHASH, to provide authenticated encryption:
+ *
+ * - Any block cipher with 16-byte blocks can be used with GCM.
+ *
+ * - The nonce can have any length, from 0 up to 2^64-1 bits; however,
+ * 96-bit nonces (12 bytes) are recommended (nonces with a length
+ * distinct from 12 bytes are internally hashed, which risks reusing
+ * nonce value with a small but not always negligible probability).
+ *
+ * - Additional authenticated data may have length up to 2^64-1 bits.
+ *
+ * - Message length may range up to 2^39-256 bits at most.
+ *
+ * - The authentication tag has length 16 bytes.
+ *
+ * The GCM initialisation function receives as parameter an
+ * _initialised_ block cipher implementation context, with the secret
+ * key already set. A pointer to that context will be kept within the
+ * GCM context structure. It is up to the caller to allocate and
+ * initialise that block cipher context.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_aead_class *vtable;
+
+#ifndef BR_DOXYGEN_IGNORE
+ const br_block_ctr_class **bctx;
+ br_ghash gh;
+ unsigned char h[16];
+ unsigned char j0_1[12];
+ unsigned char buf[16];
+ unsigned char y[16];
+ uint32_t j0_2, jc;
+ uint64_t count_aad, count_ctr;
+#endif
+} br_gcm_context;
+
+/**
+ * \brief Initialize a GCM context.
+ *
+ * A block cipher implementation, with its initialised context structure,
+ * is provided. The block cipher MUST use 16-byte blocks in CTR mode,
+ * and its secret key MUST have been already set in the provided context.
+ * A GHASH implementation must also be provided. The parameters are linked
+ * in the GCM context.
+ *
+ * After this function has been called, the `br_gcm_reset()` function must
+ * be called, to provide the IV for GCM computation.
+ *
+ * \param ctx GCM context structure.
+ * \param bctx block cipher context (already initialised with secret key).
+ * \param gh GHASH implementation.
+ */
+void br_gcm_init(br_gcm_context *ctx,
+ const br_block_ctr_class **bctx, br_ghash gh);
+
+/**
+ * \brief Reset a GCM context.
+ *
+ * This function resets an already initialised GCM context for a new
+ * computation run. Implementations and keys are conserved. This function
+ * can be called at any time; it cancels any ongoing GCM computation that
+ * uses the provided context structure.
+ *
+ * The provided IV is a _nonce_. It is critical to GCM security that IV
+ * values are not repeated for the same encryption key. IV can have
+ * arbitrary length (up to 2^64-1 bits), but the "normal" length is
+ * 96 bits (12 bytes).
+ *
+ * \param ctx GCM context structure.
+ * \param iv GCM nonce to use.
+ * \param len GCM nonce length (in bytes).
+ */
+void br_gcm_reset(br_gcm_context *ctx, const void *iv, size_t len);
+
+/**
+ * \brief Inject additional authenticated data into GCM.
+ *
+ * The provided data is injected into a running GCM computation. Additional
+ * data must be injected _before_ the call to `br_gcm_flip()`.
+ * Additional data can be injected in several chunks of arbitrary length;
+ * the maximum total size of additional authenticated data is 2^64-1
+ * bits.
+ *
+ * \param ctx GCM context structure.
+ * \param data pointer to additional authenticated data.
+ * \param len length of additional authenticated data (in bytes).
+ */
+void br_gcm_aad_inject(br_gcm_context *ctx, const void *data, size_t len);
+
+/**
+ * \brief Finish injection of additional authenticated data into GCM.
+ *
+ * This function MUST be called before beginning the actual encryption
+ * or decryption (with `br_gcm_run()`), even if no additional authenticated
+ * data was injected. No additional authenticated data may be injected
+ * after this function call.
+ *
+ * \param ctx GCM context structure.
+ */
+void br_gcm_flip(br_gcm_context *ctx);
+
+/**
+ * \brief Encrypt or decrypt some data with GCM.
+ *
+ * Data encryption or decryption can be done after `br_gcm_flip()`
+ * has been called on the context. If `encrypt` is non-zero, then the
+ * provided data shall be plaintext, and it is encrypted in place.
+ * Otherwise, the data shall be ciphertext, and it is decrypted in place.
+ *
+ * Data may be provided in several chunks of arbitrary length. The maximum
+ * total length for data is 2^39-256 bits, i.e. about 65 gigabytes.
+ *
+ * \param ctx GCM context structure.
+ * \param encrypt non-zero for encryption, zero for decryption.
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ */
+void br_gcm_run(br_gcm_context *ctx, int encrypt, void *data, size_t len);
+
+/**
+ * \brief Compute GCM authentication tag.
+ *
+ * Compute the GCM authentication tag. The tag is a 16-byte value which
+ * is written in the provided `tag` buffer. This call terminates the
+ * GCM run: no data may be processed with that GCM context afterwards,
+ * until `br_gcm_reset()` is called to initiate a new GCM run.
+ *
+ * The tag value must normally be sent along with the encrypted data.
+ * When decrypting, the tag value must be recomputed and compared with
+ * the received tag: if the two tag values differ, then either the tag
+ * or the encrypted data was altered in transit. As an alternative to
+ * this function, the `br_gcm_check_tag()` function can be used to
+ * compute and check the tag value.
+ *
+ * \param ctx GCM context structure.
+ * \param tag destination buffer for the tag (16 bytes).
+ */
+void br_gcm_get_tag(br_gcm_context *ctx, void *tag);
+
+/**
+ * \brief Compute and check GCM authentication tag.
+ *
+ * This function is an alternative to `br_gcm_get_tag()`, normally used
+ * on the receiving end (i.e. when decrypting value). The tag value is
+ * recomputed and compared with the provided tag value. If they match, 1
+ * is returned; on mismatch, 0 is returned. A returned value of 0 means
+ * that the data or the tag was altered in transit, normally leading to
+ * wholesale rejection of the complete message.
+ *
+ * \param ctx GCM context structure.
+ * \param tag tag value to compare with (16 bytes).
+ * \return 1 on success (exact match of tag value), 0 otherwise.
+ */
+uint32_t br_gcm_check_tag(br_gcm_context *ctx, const void *tag);
+
+/**
+ * \brief Compute GCM authentication tag (with truncation).
+ *
+ * This function is similar to `br_gcm_get_tag()`, except that it allows
+ * the tag to be truncated to a smaller length. The intended tag length
+ * is provided as `len` (in bytes); it MUST be no more than 16, but
+ * it may be smaller. Note that decreasing tag length mechanically makes
+ * forgeries easier; NIST SP 800-38D specifies that the tag length shall
+ * lie between 12 and 16 bytes (inclusive), but may be truncated down to
+ * 4 or 8 bytes, for specific applications that can tolerate it. It must
+ * also be noted that successful forgeries leak information on the
+ * authentication key, making subsequent forgeries easier. Therefore,
+ * tag truncation, and in particular truncation to sizes lower than 12
+ * bytes, shall be envisioned only with great care.
+ *
+ * The tag is written in the provided `tag` buffer. This call terminates
+ * the GCM run: no data may be processed with that GCM context
+ * afterwards, until `br_gcm_reset()` is called to initiate a new GCM
+ * run.
+ *
+ * The tag value must normally be sent along with the encrypted data.
+ * When decrypting, the tag value must be recomputed and compared with
+ * the received tag: if the two tag values differ, then either the tag
+ * or the encrypted data was altered in transit. As an alternative to
+ * this function, the `br_gcm_check_tag_trunc()` function can be used to
+ * compute and check the tag value.
+ *
+ * \param ctx GCM context structure.
+ * \param tag destination buffer for the tag.
+ * \param len tag length (16 bytes or less).
+ */
+void br_gcm_get_tag_trunc(br_gcm_context *ctx, void *tag, size_t len);
+
+/**
+ * \brief Compute and check GCM authentication tag (with truncation).
+ *
+ * This function is an alternative to `br_gcm_get_tag_trunc()`, normally used
+ * on the receiving end (i.e. when decrypting value). The tag value is
+ * recomputed and compared with the provided tag value. If they match, 1
+ * is returned; on mismatch, 0 is returned. A returned value of 0 means
+ * that the data or the tag was altered in transit, normally leading to
+ * wholesale rejection of the complete message.
+ *
+ * Tag length MUST be 16 bytes or less. The normal GCM tag length is 16
+ * bytes. See `br_check_tag_trunc()` for some discussion on the potential
+ * perils of truncating authentication tags.
+ *
+ * \param ctx GCM context structure.
+ * \param tag tag value to compare with.
+ * \param len tag length (in bytes).
+ * \return 1 on success (exact match of tag value), 0 otherwise.
+ */
+uint32_t br_gcm_check_tag_trunc(br_gcm_context *ctx,
+ const void *tag, size_t len);
+
+/**
+ * \brief Class instance for GCM.
+ */
+extern const br_aead_class br_gcm_vtable;
+
+/**
+ * \brief Context structure for EAX.
+ *
+ * EAX is an AEAD mode that combines a block cipher in CTR mode with
+ * CBC-MAC using the same block cipher and the same key, to provide
+ * authenticated encryption:
+ *
+ * - Any block cipher with 16-byte blocks can be used with EAX
+ * (technically, other block sizes are defined as well, but this
+ * is not implemented by these functions; shorter blocks also
+ * imply numerous security issues).
+ *
+ * - The nonce can have any length, as long as nonce values are
+ * not reused (thus, if nonces are randomly selected, the nonce
+ * size should be such that reuse probability is negligible).
+ *
+ * - Additional authenticated data length is unlimited.
+ *
+ * - Message length is unlimited.
+ *
+ * - The authentication tag has length 16 bytes.
+ *
+ * The EAX initialisation function receives as parameter an
+ * _initialised_ block cipher implementation context, with the secret
+ * key already set. A pointer to that context will be kept within the
+ * EAX context structure. It is up to the caller to allocate and
+ * initialise that block cipher context.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_aead_class *vtable;
+
+#ifndef BR_DOXYGEN_IGNORE
+ const br_block_ctrcbc_class **bctx;
+ unsigned char L2[16];
+ unsigned char L4[16];
+ unsigned char nonce[16];
+ unsigned char head[16];
+ unsigned char ctr[16];
+ unsigned char cbcmac[16];
+ unsigned char buf[16];
+ size_t ptr;
+#endif
+} br_eax_context;
+
+/**
+ * \brief EAX captured state.
+ *
+ * Some internal values computed by EAX may be captured at various
+ * points, and reused for another EAX run with the same secret key,
+ * for lower per-message overhead. Captured values do not depend on
+ * the nonce.
+ */
+typedef struct {
+#ifndef BR_DOXYGEN_IGNORE
+ unsigned char st[3][16];
+#endif
+} br_eax_state;
+
+/**
+ * \brief Initialize an EAX context.
+ *
+ * A block cipher implementation, with its initialised context
+ * structure, is provided. The block cipher MUST use 16-byte blocks in
+ * CTR + CBC-MAC mode, and its secret key MUST have been already set in
+ * the provided context. The parameters are linked in the EAX context.
+ *
+ * After this function has been called, the `br_eax_reset()` function must
+ * be called, to provide the nonce for EAX computation.
+ *
+ * \param ctx EAX context structure.
+ * \param bctx block cipher context (already initialised with secret key).
+ */
+void br_eax_init(br_eax_context *ctx, const br_block_ctrcbc_class **bctx);
+
+/**
+ * \brief Capture pre-AAD state.
+ *
+ * This function precomputes key-dependent data, and stores it in the
+ * provided `st` structure. This structure should then be used with
+ * `br_eax_reset_pre_aad()`, or updated with `br_eax_get_aad_mac()`
+ * and then used with `br_eax_reset_post_aad()`.
+ *
+ * The EAX context structure is unmodified by this call.
+ *
+ * \param ctx EAX context structure.
+ * \param st recipient for captured state.
+ */
+void br_eax_capture(const br_eax_context *ctx, br_eax_state *st);
+
+/**
+ * \brief Reset an EAX context.
+ *
+ * This function resets an already initialised EAX context for a new
+ * computation run. Implementations and keys are conserved. This function
+ * can be called at any time; it cancels any ongoing EAX computation that
+ * uses the provided context structure.
+ *
+ * It is critical to EAX security that nonce values are not repeated for
+ * the same encryption key. Nonces can have arbitrary length. If nonces
+ * are randomly generated, then a nonce length of at least 128 bits (16
+ * bytes) is recommended, to make nonce reuse probability sufficiently
+ * low.
+ *
+ * \param ctx EAX context structure.
+ * \param nonce EAX nonce to use.
+ * \param len EAX nonce length (in bytes).
+ */
+void br_eax_reset(br_eax_context *ctx, const void *nonce, size_t len);
+
+/**
+ * \brief Reset an EAX context with a pre-AAD captured state.
+ *
+ * This function is an alternative to `br_eax_reset()`, that reuses a
+ * previously captured state structure for lower per-message overhead.
+ * The state should have been populated with `br_eax_capture_state()`
+ * but not updated with `br_eax_get_aad_mac()`.
+ *
+ * After this function is called, additional authenticated data MUST
+ * be injected. At least one byte of additional authenticated data
+ * MUST be provided with `br_eax_aad_inject()`; computation result will
+ * be incorrect if `br_eax_flip()` is called right away.
+ *
+ * After injection of the AAD and call to `br_eax_flip()`, at least
+ * one message byte must be provided. Empty messages are not supported
+ * with this reset mode.
+ *
+ * \param ctx EAX context structure.
+ * \param st pre-AAD captured state.
+ * \param nonce EAX nonce to use.
+ * \param len EAX nonce length (in bytes).
+ */
+void br_eax_reset_pre_aad(br_eax_context *ctx, const br_eax_state *st,
+ const void *nonce, size_t len);
+
+/**
+ * \brief Reset an EAX context with a post-AAD captured state.
+ *
+ * This function is an alternative to `br_eax_reset()`, that reuses a
+ * previously captured state structure for lower per-message overhead.
+ * The state should have been populated with `br_eax_capture_state()`
+ * and then updated with `br_eax_get_aad_mac()`.
+ *
+ * After this function is called, message data MUST be injected. The
+ * `br_eax_flip()` function MUST NOT be called. At least one byte of
+ * message data MUST be provided with `br_eax_run()`; empty messages
+ * are not supported with this reset mode.
+ *
+ * \param ctx EAX context structure.
+ * \param st post-AAD captured state.
+ * \param nonce EAX nonce to use.
+ * \param len EAX nonce length (in bytes).
+ */
+void br_eax_reset_post_aad(br_eax_context *ctx, const br_eax_state *st,
+ const void *nonce, size_t len);
+
+/**
+ * \brief Inject additional authenticated data into EAX.
+ *
+ * The provided data is injected into a running EAX computation. Additional
+ * data must be injected _before_ the call to `br_eax_flip()`.
+ * Additional data can be injected in several chunks of arbitrary length;
+ * the total amount of additional authenticated data is unlimited.
+ *
+ * \param ctx EAX context structure.
+ * \param data pointer to additional authenticated data.
+ * \param len length of additional authenticated data (in bytes).
+ */
+void br_eax_aad_inject(br_eax_context *ctx, const void *data, size_t len);
+
+/**
+ * \brief Finish injection of additional authenticated data into EAX.
+ *
+ * This function MUST be called before beginning the actual encryption
+ * or decryption (with `br_eax_run()`), even if no additional authenticated
+ * data was injected. No additional authenticated data may be injected
+ * after this function call.
+ *
+ * \param ctx EAX context structure.
+ */
+void br_eax_flip(br_eax_context *ctx);
+
+/**
+ * \brief Obtain a copy of the MAC on additional authenticated data.
+ *
+ * This function may be called only after `br_eax_flip()`; it copies the
+ * AAD-specific MAC value into the provided state. The MAC value depends
+ * on the secret key and the additional data itself, but not on the
+ * nonce. The updated state `st` is meant to be used as parameter for a
+ * further `br_eax_reset_post_aad()` call.
+ *
+ * \param ctx EAX context structure.
+ * \param st captured state to update.
+ */
+static inline void
+br_eax_get_aad_mac(const br_eax_context *ctx, br_eax_state *st)
+{
+ memcpy(st->st[1], ctx->head, sizeof ctx->head);
+}
+
+/**
+ * \brief Encrypt or decrypt some data with EAX.
+ *
+ * Data encryption or decryption can be done after `br_eax_flip()`
+ * has been called on the context. If `encrypt` is non-zero, then the
+ * provided data shall be plaintext, and it is encrypted in place.
+ * Otherwise, the data shall be ciphertext, and it is decrypted in place.
+ *
+ * Data may be provided in several chunks of arbitrary length.
+ *
+ * \param ctx EAX context structure.
+ * \param encrypt non-zero for encryption, zero for decryption.
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ */
+void br_eax_run(br_eax_context *ctx, int encrypt, void *data, size_t len);
+
+/**
+ * \brief Compute EAX authentication tag.
+ *
+ * Compute the EAX authentication tag. The tag is a 16-byte value which
+ * is written in the provided `tag` buffer. This call terminates the
+ * EAX run: no data may be processed with that EAX context afterwards,
+ * until `br_eax_reset()` is called to initiate a new EAX run.
+ *
+ * The tag value must normally be sent along with the encrypted data.
+ * When decrypting, the tag value must be recomputed and compared with
+ * the received tag: if the two tag values differ, then either the tag
+ * or the encrypted data was altered in transit. As an alternative to
+ * this function, the `br_eax_check_tag()` function can be used to
+ * compute and check the tag value.
+ *
+ * \param ctx EAX context structure.
+ * \param tag destination buffer for the tag (16 bytes).
+ */
+void br_eax_get_tag(br_eax_context *ctx, void *tag);
+
+/**
+ * \brief Compute and check EAX authentication tag.
+ *
+ * This function is an alternative to `br_eax_get_tag()`, normally used
+ * on the receiving end (i.e. when decrypting value). The tag value is
+ * recomputed and compared with the provided tag value. If they match, 1
+ * is returned; on mismatch, 0 is returned. A returned value of 0 means
+ * that the data or the tag was altered in transit, normally leading to
+ * wholesale rejection of the complete message.
+ *
+ * \param ctx EAX context structure.
+ * \param tag tag value to compare with (16 bytes).
+ * \return 1 on success (exact match of tag value), 0 otherwise.
+ */
+uint32_t br_eax_check_tag(br_eax_context *ctx, const void *tag);
+
+/**
+ * \brief Compute EAX authentication tag (with truncation).
+ *
+ * This function is similar to `br_eax_get_tag()`, except that it allows
+ * the tag to be truncated to a smaller length. The intended tag length
+ * is provided as `len` (in bytes); it MUST be no more than 16, but
+ * it may be smaller. Note that decreasing tag length mechanically makes
+ * forgeries easier; NIST SP 800-38D specifies that the tag length shall
+ * lie between 12 and 16 bytes (inclusive), but may be truncated down to
+ * 4 or 8 bytes, for specific applications that can tolerate it. It must
+ * also be noted that successful forgeries leak information on the
+ * authentication key, making subsequent forgeries easier. Therefore,
+ * tag truncation, and in particular truncation to sizes lower than 12
+ * bytes, shall be envisioned only with great care.
+ *
+ * The tag is written in the provided `tag` buffer. This call terminates
+ * the EAX run: no data may be processed with that EAX context
+ * afterwards, until `br_eax_reset()` is called to initiate a new EAX
+ * run.
+ *
+ * The tag value must normally be sent along with the encrypted data.
+ * When decrypting, the tag value must be recomputed and compared with
+ * the received tag: if the two tag values differ, then either the tag
+ * or the encrypted data was altered in transit. As an alternative to
+ * this function, the `br_eax_check_tag_trunc()` function can be used to
+ * compute and check the tag value.
+ *
+ * \param ctx EAX context structure.
+ * \param tag destination buffer for the tag.
+ * \param len tag length (16 bytes or less).
+ */
+void br_eax_get_tag_trunc(br_eax_context *ctx, void *tag, size_t len);
+
+/**
+ * \brief Compute and check EAX authentication tag (with truncation).
+ *
+ * This function is an alternative to `br_eax_get_tag_trunc()`, normally used
+ * on the receiving end (i.e. when decrypting value). The tag value is
+ * recomputed and compared with the provided tag value. If they match, 1
+ * is returned; on mismatch, 0 is returned. A returned value of 0 means
+ * that the data or the tag was altered in transit, normally leading to
+ * wholesale rejection of the complete message.
+ *
+ * Tag length MUST be 16 bytes or less. The normal EAX tag length is 16
+ * bytes. See `br_check_tag_trunc()` for some discussion on the potential
+ * perils of truncating authentication tags.
+ *
+ * \param ctx EAX context structure.
+ * \param tag tag value to compare with.
+ * \param len tag length (in bytes).
+ * \return 1 on success (exact match of tag value), 0 otherwise.
+ */
+uint32_t br_eax_check_tag_trunc(br_eax_context *ctx,
+ const void *tag, size_t len);
+
+/**
+ * \brief Class instance for EAX.
+ */
+extern const br_aead_class br_eax_vtable;
+
+/**
+ * \brief Context structure for CCM.
+ *
+ * CCM is an AEAD mode that combines a block cipher in CTR mode with
+ * CBC-MAC using the same block cipher and the same key, to provide
+ * authenticated encryption:
+ *
+ * - Any block cipher with 16-byte blocks can be used with CCM
+ * (technically, other block sizes are defined as well, but this
+ * is not implemented by these functions; shorter blocks also
+ * imply numerous security issues).
+ *
+ * - The authentication tag length, and plaintext length, MUST be
+ * known when starting processing data. Plaintext and ciphertext
+ * can still be provided by chunks, but the total size must match
+ * the value provided upon initialisation.
+ *
+ * - The nonce length is constrained between 7 and 13 bytes (inclusive).
+ * Furthermore, the plaintext length, when encoded, must fit over
+ * 15-nonceLen bytes; thus, if the nonce has length 13 bytes, then
+ * the plaintext length cannot exceed 65535 bytes.
+ *
+ * - Additional authenticated data length is practically unlimited
+ * (formal limit is at 2^64 bytes).
+ *
+ * - The authentication tag has length 4 to 16 bytes (even values only).
+ *
+ * The CCM initialisation function receives as parameter an
+ * _initialised_ block cipher implementation context, with the secret
+ * key already set. A pointer to that context will be kept within the
+ * CCM context structure. It is up to the caller to allocate and
+ * initialise that block cipher context.
+ */
+typedef struct {
+#ifndef BR_DOXYGEN_IGNORE
+ const br_block_ctrcbc_class **bctx;
+ unsigned char ctr[16];
+ unsigned char cbcmac[16];
+ unsigned char tagmask[16];
+ unsigned char buf[16];
+ size_t ptr;
+ size_t tag_len;
+#endif
+} br_ccm_context;
+
+/**
+ * \brief Initialize a CCM context.
+ *
+ * A block cipher implementation, with its initialised context
+ * structure, is provided. The block cipher MUST use 16-byte blocks in
+ * CTR + CBC-MAC mode, and its secret key MUST have been already set in
+ * the provided context. The parameters are linked in the CCM context.
+ *
+ * After this function has been called, the `br_ccm_reset()` function must
+ * be called, to provide the nonce for CCM computation.
+ *
+ * \param ctx CCM context structure.
+ * \param bctx block cipher context (already initialised with secret key).
+ */
+void br_ccm_init(br_ccm_context *ctx, const br_block_ctrcbc_class **bctx);
+
+/**
+ * \brief Reset a CCM context.
+ *
+ * This function resets an already initialised CCM context for a new
+ * computation run. Implementations and keys are conserved. This function
+ * can be called at any time; it cancels any ongoing CCM computation that
+ * uses the provided context structure.
+ *
+ * The `aad_len` parameter contains the total length, in bytes, of the
+ * additional authenticated data. It may be zero. That length MUST be
+ * exact.
+ *
+ * The `data_len` parameter contains the total length, in bytes, of the
+ * data that will be injected (plaintext or ciphertext). That length MUST
+ * be exact. Moreover, that length MUST be less than 2^(8*(15-nonce_len)).
+ *
+ * The nonce length (`nonce_len`), in bytes, must be in the 7..13 range
+ * (inclusive).
+ *
+ * The tag length (`tag_len`), in bytes, must be in the 4..16 range, and
+ * be an even integer. Short tags mechanically allow for higher forgery
+ * probabilities; hence, tag sizes smaller than 12 bytes shall be used only
+ * with care.
+ *
+ * It is critical to CCM security that nonce values are not repeated for
+ * the same encryption key. Random generation of nonces is not generally
+ * recommended, due to the relatively small maximum nonce value.
+ *
+ * Returned value is 1 on success, 0 on error. An error is reported if
+ * the tag or nonce length is out of range, or if the
+ * plaintext/ciphertext length cannot be encoded with the specified
+ * nonce length.
+ *
+ * \param ctx CCM context structure.
+ * \param nonce CCM nonce to use.
+ * \param nonce_len CCM nonce length (in bytes, 7 to 13).
+ * \param aad_len additional authenticated data length (in bytes).
+ * \param data_len plaintext/ciphertext length (in bytes).
+ * \param tag_len tag length (in bytes).
+ * \return 1 on success, 0 on error.
+ */
+int br_ccm_reset(br_ccm_context *ctx, const void *nonce, size_t nonce_len,
+ uint64_t aad_len, uint64_t data_len, size_t tag_len);
+
+/**
+ * \brief Inject additional authenticated data into CCM.
+ *
+ * The provided data is injected into a running CCM computation. Additional
+ * data must be injected _before_ the call to `br_ccm_flip()`.
+ * Additional data can be injected in several chunks of arbitrary length,
+ * but the total amount MUST exactly match the value which was provided
+ * to `br_ccm_reset()`.
+ *
+ * \param ctx CCM context structure.
+ * \param data pointer to additional authenticated data.
+ * \param len length of additional authenticated data (in bytes).
+ */
+void br_ccm_aad_inject(br_ccm_context *ctx, const void *data, size_t len);
+
+/**
+ * \brief Finish injection of additional authenticated data into CCM.
+ *
+ * This function MUST be called before beginning the actual encryption
+ * or decryption (with `br_ccm_run()`), even if no additional authenticated
+ * data was injected. No additional authenticated data may be injected
+ * after this function call.
+ *
+ * \param ctx CCM context structure.
+ */
+void br_ccm_flip(br_ccm_context *ctx);
+
+/**
+ * \brief Encrypt or decrypt some data with CCM.
+ *
+ * Data encryption or decryption can be done after `br_ccm_flip()`
+ * has been called on the context. If `encrypt` is non-zero, then the
+ * provided data shall be plaintext, and it is encrypted in place.
+ * Otherwise, the data shall be ciphertext, and it is decrypted in place.
+ *
+ * Data may be provided in several chunks of arbitrary length, provided
+ * that the total length exactly matches the length provided to the
+ * `br_ccm_reset()` call.
+ *
+ * \param ctx CCM context structure.
+ * \param encrypt non-zero for encryption, zero for decryption.
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ */
+void br_ccm_run(br_ccm_context *ctx, int encrypt, void *data, size_t len);
+
+/**
+ * \brief Compute CCM authentication tag.
+ *
+ * Compute the CCM authentication tag. This call terminates the CCM
+ * run: all data must have been injected with `br_ccm_run()` (in zero,
+ * one or more successive calls). After this function has been called,
+ * no more data can br processed; a `br_ccm_reset()` call is required
+ * to start a new message.
+ *
+ * The tag length was provided upon context initialisation (last call
+ * to `br_ccm_reset()`); it is returned by this function.
+ *
+ * The tag value must normally be sent along with the encrypted data.
+ * When decrypting, the tag value must be recomputed and compared with
+ * the received tag: if the two tag values differ, then either the tag
+ * or the encrypted data was altered in transit. As an alternative to
+ * this function, the `br_ccm_check_tag()` function can be used to
+ * compute and check the tag value.
+ *
+ * \param ctx CCM context structure.
+ * \param tag destination buffer for the tag (up to 16 bytes).
+ * \return the tag length (in bytes).
+ */
+size_t br_ccm_get_tag(br_ccm_context *ctx, void *tag);
+
+/**
+ * \brief Compute and check CCM authentication tag.
+ *
+ * This function is an alternative to `br_ccm_get_tag()`, normally used
+ * on the receiving end (i.e. when decrypting value). The tag value is
+ * recomputed and compared with the provided tag value. If they match, 1
+ * is returned; on mismatch, 0 is returned. A returned value of 0 means
+ * that the data or the tag was altered in transit, normally leading to
+ * wholesale rejection of the complete message.
+ *
+ * \param ctx CCM context structure.
+ * \param tag tag value to compare with (up to 16 bytes).
+ * \return 1 on success (exact match of tag value), 0 otherwise.
+ */
+uint32_t br_ccm_check_tag(br_ccm_context *ctx, const void *tag);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/inc/bearssl_block.h b/inc/bearssl_block.h
new file mode 100644
index 000000000000..683a4906d061
--- /dev/null
+++ b/inc/bearssl_block.h
@@ -0,0 +1,2618 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef BR_BEARSSL_BLOCK_H__
+#define BR_BEARSSL_BLOCK_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file bearssl_block.h
+ *
+ * # Block Ciphers and Symmetric Ciphers
+ *
+ * This file documents the API for block ciphers and other symmetric
+ * ciphers.
+ *
+ *
+ * ## Procedural API
+ *
+ * For a block cipher implementation, up to three separate sets of
+ * functions are provided, for CBC encryption, CBC decryption, and CTR
+ * encryption/decryption. Each set has its own context structure,
+ * initialised with the encryption key.
+ *
+ * For CBC encryption and decryption, the data to encrypt or decrypt is
+ * referenced as a sequence of blocks. The implementations assume that
+ * there is no partial block; no padding is applied or removed. The
+ * caller is responsible for handling any kind of padding.
+ *
+ * Function for CTR encryption are defined only for block ciphers with
+ * blocks of 16 bytes or more (i.e. AES, but not DES/3DES).
+ *
+ * Each implemented block cipher is identified by an "internal name"
+ * from which are derived the names of structures and functions that
+ * implement the cipher. For the block cipher of internal name "`xxx`",
+ * the following are defined:
+ *
+ * - `br_xxx_BLOCK_SIZE`
+ *
+ * A macro that evaluates to the block size (in bytes) of the
+ * cipher. For all implemented block ciphers, this value is a
+ * power of two.
+ *
+ * - `br_xxx_cbcenc_keys`
+ *
+ * Context structure that contains the subkeys resulting from the key
+ * expansion. These subkeys are appropriate for CBC encryption. The
+ * structure first field is called `vtable` and points to the
+ * appropriate OOP structure.
+ *
+ * - `br_xxx_cbcenc_init(br_xxx_cbcenc_keys *ctx, const void *key, size_t len)`
+ *
+ * Perform key expansion: subkeys for CBC encryption are computed and
+ * written in the provided context structure. The key length MUST be
+ * adequate for the implemented block cipher. This function also sets
+ * the `vtable` field.
+ *
+ * - `br_xxx_cbcenc_run(const br_xxx_cbcenc_keys *ctx, void *iv, void *data, size_t len)`
+ *
+ * Perform CBC encryption of `len` bytes, in place. The encrypted data
+ * replaces the cleartext. `len` MUST be a multiple of the block length
+ * (if it is not, the function may loop forever or overflow a buffer).
+ * The IV is provided with the `iv` pointer; it is also updated with
+ * a copy of the last encrypted block.
+ *
+ * - `br_xxx_cbcdec_keys`
+ *
+ * Context structure that contains the subkeys resulting from the key
+ * expansion. These subkeys are appropriate for CBC decryption. The
+ * structure first field is called `vtable` and points to the
+ * appropriate OOP structure.
+ *
+ * - `br_xxx_cbcdec_init(br_xxx_cbcenc_keys *ctx, const void *key, size_t len)`
+ *
+ * Perform key expansion: subkeys for CBC decryption are computed and
+ * written in the provided context structure. The key length MUST be
+ * adequate for the implemented block cipher. This function also sets
+ * the `vtable` field.
+ *
+ * - `br_xxx_cbcdec_run(const br_xxx_cbcdec_keys *ctx, void *iv, void *data, size_t num_blocks)`
+ *
+ * Perform CBC decryption of `len` bytes, in place. The decrypted data
+ * replaces the ciphertext. `len` MUST be a multiple of the block length
+ * (if it is not, the function may loop forever or overflow a buffer).
+ * The IV is provided with the `iv` pointer; it is also updated with
+ * a copy of the last _encrypted_ block.
+ *
+ * - `br_xxx_ctr_keys`
+ *
+ * Context structure that contains the subkeys resulting from the key
+ * expansion. These subkeys are appropriate for CTR encryption and
+ * decryption. The structure first field is called `vtable` and
+ * points to the appropriate OOP structure.
+ *
+ * - `br_xxx_ctr_init(br_xxx_ctr_keys *ctx, const void *key, size_t len)`
+ *
+ * Perform key expansion: subkeys for CTR encryption and decryption
+ * are computed and written in the provided context structure. The
+ * key length MUST be adequate for the implemented block cipher. This
+ * function also sets the `vtable` field.
+ *
+ * - `br_xxx_ctr_run(const br_xxx_ctr_keys *ctx, const void *iv, uint32_t cc, void *data, size_t len)` (returns `uint32_t`)
+ *
+ * Perform CTR encryption/decryption of some data. Processing is done
+ * "in place" (the output data replaces the input data). This function
+ * implements the "standard incrementing function" from NIST SP800-38A,
+ * annex B: the IV length shall be 4 bytes less than the block size
+ * (i.e. 12 bytes for AES) and the counter is the 32-bit value starting
+ * with `cc`. The data length (`len`) is not necessarily a multiple of
+ * the block size. The new counter value is returned, which supports
+ * chunked processing, provided that each chunk length (except possibly
+ * the last one) is a multiple of the block size.
+ *
+ * - `br_xxx_ctrcbc_keys`
+ *
+ * Context structure that contains the subkeys resulting from the
+ * key expansion. These subkeys are appropriate for doing combined
+ * CTR encryption/decryption and CBC-MAC, as used in the CCM and EAX
+ * authenticated encryption modes. The structure first field is
+ * called `vtable` and points to the appropriate OOP structure.
+ *
+ * - `br_xxx_ctrcbc_init(br_xxx_ctr_keys *ctx, const void *key, size_t len)`
+ *
+ * Perform key expansion: subkeys for combined CTR
+ * encryption/decryption and CBC-MAC are computed and written in the
+ * provided context structure. The key length MUST be adequate for
+ * the implemented block cipher. This function also sets the
+ * `vtable` field.
+ *
+ * - `br_xxx_ctrcbc_encrypt(const br_xxx_ctrcbc_keys *ctx, void *ctr, void *cbcmac, void *data, size_t len)`
+ *
+ * Perform CTR encryption of some data, and CBC-MAC. Processing is
+ * done "in place" (the output data replaces the input data). This
+ * function applies CTR encryption on the data, using a full
+ * block-size counter (i.e. for 128-bit blocks, the counter is
+ * incremented as a 128-bit value). The 'ctr' array contains the
+ * initial value for the counter (used in the first block) and it is
+ * updated with the new value after data processing. The 'cbcmac'
+ * value shall point to a block-sized value which is used as IV for
+ * CBC-MAC, computed over the encrypted data (output of CTR
+ * encryption); the resulting CBC-MAC is written over 'cbcmac' on
+ * output.
+ *
+ * The data length MUST be a multiple of the block size.
+ *
+ * - `br_xxx_ctrcbc_decrypt(const br_xxx_ctrcbc_keys *ctx, void *ctr, void *cbcmac, void *data, size_t len)`
+ *
+ * Perform CTR decryption of some data, and CBC-MAC. Processing is
+ * done "in place" (the output data replaces the input data). This
+ * function applies CTR decryption on the data, using a full
+ * block-size counter (i.e. for 128-bit blocks, the counter is
+ * incremented as a 128-bit value). The 'ctr' array contains the
+ * initial value for the counter (used in the first block) and it is
+ * updated with the new value after data processing. The 'cbcmac'
+ * value shall point to a block-sized value which is used as IV for
+ * CBC-MAC, computed over the encrypted data (input of CTR
+ * encryption); the resulting CBC-MAC is written over 'cbcmac' on
+ * output.
+ *
+ * The data length MUST be a multiple of the block size.
+ *
+ * - `br_xxx_ctrcbc_ctr(const br_xxx_ctrcbc_keys *ctx, void *ctr, void *data, size_t len)`
+ *
+ * Perform CTR encryption or decryption of the provided data. The
+ * data is processed "in place" (the output data replaces the input
+ * data). A full block-sized counter is applied (i.e. for 128-bit
+ * blocks, the counter is incremented as a 128-bit value). The 'ctr'
+ * array contains the initial value for the counter (used in the
+ * first block), and it is updated with the new value after data
+ * processing.
+ *
+ * The data length MUST be a multiple of the block size.
+ *
+ * - `br_xxx_ctrcbc_mac(const br_xxx_ctrcbc_keys *ctx, void *cbcmac, const void *data, size_t len)`
+ *
+ * Compute CBC-MAC over the provided data. The IV for CBC-MAC is
+ * provided as 'cbcmac'; the output is written over the same array.
+ * The data itself is untouched. The data length MUST be a multiple
+ * of the block size.
+ *
+ *
+ * It shall be noted that the key expansion functions return `void`. If
+ * the provided key length is not allowed, then there will be no error
+ * reporting; implementations need not validate the key length, thus an
+ * invalid key length may result in undefined behaviour (e.g. buffer
+ * overflow).
+ *
+ * Subkey structures contain no interior pointer, and no external
+ * resources are allocated upon key expansion. They can thus be
+ * discarded without any explicit deallocation.
+ *
+ *
+ * ## Object-Oriented API
+ *
+ * Each context structure begins with a field (called `vtable`) that
+ * points to an instance of a structure that references the relevant
+ * functions through pointers. Each such structure contains the
+ * following:
+ *
+ * - `context_size`
+ *
+ * The size (in bytes) of the context structure for subkeys.
+ *
+ * - `block_size`
+ *
+ * The cipher block size (in bytes).
+ *
+ * - `log_block_size`
+ *
+ * The base-2 logarithm of cipher block size (e.g. 4 for blocks
+ * of 16 bytes).
+ *
+ * - `init`
+ *
+ * Pointer to the key expansion function.
+ *
+ * - `run`
+ *
+ * Pointer to the encryption/decryption function.
+ *
+ * For combined CTR/CBC-MAC encryption, the `vtable` has a slightly
+ * different structure:
+ *
+ * - `context_size`
+ *
+ * The size (in bytes) of the context structure for subkeys.
+ *
+ * - `block_size`
+ *
+ * The cipher block size (in bytes).
+ *
+ * - `log_block_size`
+ *
+ * The base-2 logarithm of cipher block size (e.g. 4 for blocks
+ * of 16 bytes).
+ *
+ * - `init`
+ *
+ * Pointer to the key expansion function.
+ *
+ * - `encrypt`
+ *
+ * Pointer to the CTR encryption + CBC-MAC function.
+ *
+ * - `decrypt`
+ *
+ * Pointer to the CTR decryption + CBC-MAC function.
+ *
+ * - `ctr`
+ *
+ * Pointer to the CTR encryption/decryption function.
+ *
+ * - `mac`
+ *
+ * Pointer to the CBC-MAC function.
+ *
+ * For block cipher "`xxx`", static, constant instances of these
+ * structures are defined, under the names:
+ *
+ * - `br_xxx_cbcenc_vtable`
+ * - `br_xxx_cbcdec_vtable`
+ * - `br_xxx_ctr_vtable`
+ * - `br_xxx_ctrcbc_vtable`
+ *
+ *
+ * ## Implemented Block Ciphers
+ *
+ * Provided implementations are:
+ *
+ * | Name | Function | Block Size (bytes) | Key lengths (bytes) |
+ * | :-------- | :------- | :----------------: | :-----------------: |
+ * | aes_big | AES | 16 | 16, 24 and 32 |
+ * | aes_small | AES | 16 | 16, 24 and 32 |
+ * | aes_ct | AES | 16 | 16, 24 and 32 |
+ * | aes_ct64 | AES | 16 | 16, 24 and 32 |
+ * | aes_x86ni | AES | 16 | 16, 24 and 32 |
+ * | aes_pwr8 | AES | 16 | 16, 24 and 32 |
+ * | des_ct | DES/3DES | 8 | 8, 16 and 24 |
+ * | des_tab | DES/3DES | 8 | 8, 16 and 24 |
+ *
+ * **Note:** DES/3DES nominally uses keys of 64, 128 and 192 bits (i.e. 8,
+ * 16 and 24 bytes), but some of the bits are ignored by the algorithm, so
+ * the _effective_ key lengths, from a security point of view, are 56,
+ * 112 and 168 bits, respectively.
+ *
+ * `aes_big` is a "classical" AES implementation, using tables. It
+ * is fast but not constant-time, since it makes data-dependent array
+ * accesses.
+ *
+ * `aes_small` is an AES implementation optimized for code size. It
+ * is substantially slower than `aes_big`; it is not constant-time
+ * either.
+ *
+ * `aes_ct` is a constant-time implementation of AES; its code is about
+ * as big as that of `aes_big`, while its performance is comparable to
+ * that of `aes_small`. However, it is constant-time. This
+ * implementation should thus be considered to be the "default" AES in
+ * BearSSL, to be used unless the operational context guarantees that a
+ * non-constant-time implementation is safe, or an architecture-specific
+ * constant-time implementation can be used (e.g. using dedicated
+ * hardware opcodes).
+ *
+ * `aes_ct64` is another constant-time implementation of AES. It is
+ * similar to `aes_ct` but uses 64-bit values. On 32-bit machines,
+ * `aes_ct64` is not faster than `aes_ct`, often a bit slower, and has
+ * a larger footprint; however, on 64-bit architectures, `aes_ct64`
+ * is typically twice faster than `aes_ct` for modes that allow parallel
+ * operations (i.e. CTR, and CBC decryption, but not CBC encryption).
+ *
+ * `aes_x86ni` exists only on x86 architectures (32-bit and 64-bit). It
+ * uses the AES-NI opcodes when available.
+ *
+ * `aes_pwr8` exists only on PowerPC / POWER architectures (32-bit and
+ * 64-bit, both little-endian and big-endian). It uses the AES opcodes
+ * present in POWER8 and later.
+ *
+ * `des_tab` is a classic, table-based implementation of DES/3DES. It
+ * is not constant-time.
+ *
+ * `des_ct` is an constant-time implementation of DES/3DES. It is
+ * substantially slower than `des_tab`.
+ *
+ * ## ChaCha20 and Poly1305
+ *
+ * ChaCha20 is a stream cipher. Poly1305 is a MAC algorithm. They
+ * are described in [RFC 7539](https://tools.ietf.org/html/rfc7539).
+ *
+ * Two function pointer types are defined:
+ *
+ * - `br_chacha20_run` describes a function that implements ChaCha20
+ * only.
+ *
+ * - `br_poly1305_run` describes an implementation of Poly1305,
+ * in the AEAD combination with ChaCha20 specified in RFC 7539
+ * (the ChaCha20 implementation is provided as a function pointer).
+ *
+ * `chacha20_ct` is a straightforward implementation of ChaCha20 in
+ * plain C; it is constant-time, small, and reasonably fast.
+ *
+ * `chacha20_sse2` leverages SSE2 opcodes (on x86 architectures that
+ * support these opcodes). It is faster than `chacha20_ct`.
+ *
+ * `poly1305_ctmul` is an implementation of the ChaCha20+Poly1305 AEAD
+ * construction, where the Poly1305 part is performed with mixed 32-bit
+ * multiplications (operands are 32-bit, result is 64-bit).
+ *
+ * `poly1305_ctmul32` implements ChaCha20+Poly1305 using pure 32-bit
+ * multiplications (32-bit operands, 32-bit result). It is slower than
+ * `poly1305_ctmul`, except on some specific architectures such as
+ * the ARM Cortex M0+.
+ *
+ * `poly1305_ctmulq` implements ChaCha20+Poly1305 with mixed 64-bit
+ * multiplications (operands are 64-bit, result is 128-bit) on 64-bit
+ * platforms that support such operations.
+ *
+ * `poly1305_i15` implements ChaCha20+Poly1305 with the generic "i15"
+ * big integer implementation. It is meant mostly for testing purposes,
+ * although it can help with saving a few hundred bytes of code footprint
+ * on systems where code size is scarce.
+ */
+
+/**
+ * \brief Class type for CBC encryption implementations.
+ *
+ * A `br_block_cbcenc_class` instance points to the functions implementing
+ * a specific block cipher, when used in CBC mode for encrypting data.
+ */
+typedef struct br_block_cbcenc_class_ br_block_cbcenc_class;
+struct br_block_cbcenc_class_ {
+ /**
+ * \brief Size (in bytes) of the context structure appropriate
+ * for containing subkeys.
+ */
+ size_t context_size;
+
+ /**
+ * \brief Size of individual blocks (in bytes).
+ */
+ unsigned block_size;
+
+ /**
+ * \brief Base-2 logarithm of the size of individual blocks,
+ * expressed in bytes.
+ */
+ unsigned log_block_size;
+
+ /**
+ * \brief Initialisation function.
+ *
+ * This function sets the `vtable` field in the context structure.
+ * The key length MUST be one of the key lengths supported by
+ * the implementation.
+ *
+ * \param ctx context structure to initialise.
+ * \param key secret key.
+ * \param key_len key length (in bytes).
+ */
+ void (*init)(const br_block_cbcenc_class **ctx,
+ const void *key, size_t key_len);
+
+ /**
+ * \brief Run the CBC encryption.
+ *
+ * The `iv` parameter points to the IV for this run; it is
+ * updated with a copy of the last encrypted block. The data
+ * is encrypted "in place"; its length (`len`) MUST be a
+ * multiple of the block size.
+ *
+ * \param ctx context structure (already initialised).
+ * \param iv IV for CBC encryption (updated).
+ * \param data data to encrypt.
+ * \param len data length (in bytes, multiple of block size).
+ */
+ void (*run)(const br_block_cbcenc_class *const *ctx,
+ void *iv, void *data, size_t len);
+};
+
+/**
+ * \brief Class type for CBC decryption implementations.
+ *
+ * A `br_block_cbcdec_class` instance points to the functions implementing
+ * a specific block cipher, when used in CBC mode for decrypting data.
+ */
+typedef struct br_block_cbcdec_class_ br_block_cbcdec_class;
+struct br_block_cbcdec_class_ {
+ /**
+ * \brief Size (in bytes) of the context structure appropriate
+ * for containing subkeys.
+ */
+ size_t context_size;
+
+ /**
+ * \brief Size of individual blocks (in bytes).
+ */
+ unsigned block_size;
+
+ /**
+ * \brief Base-2 logarithm of the size of individual blocks,
+ * expressed in bytes.
+ */
+ unsigned log_block_size;
+
+ /**
+ * \brief Initialisation function.
+ *
+ * This function sets the `vtable` field in the context structure.
+ * The key length MUST be one of the key lengths supported by
+ * the implementation.
+ *
+ * \param ctx context structure to initialise.
+ * \param key secret key.
+ * \param key_len key length (in bytes).
+ */
+ void (*init)(const br_block_cbcdec_class **ctx,
+ const void *key, size_t key_len);
+
+ /**
+ * \brief Run the CBC decryption.
+ *
+ * The `iv` parameter points to the IV for this run; it is
+ * updated with a copy of the last encrypted block. The data
+ * is decrypted "in place"; its length (`len`) MUST be a
+ * multiple of the block size.
+ *
+ * \param ctx context structure (already initialised).
+ * \param iv IV for CBC decryption (updated).
+ * \param data data to decrypt.
+ * \param len data length (in bytes, multiple of block size).
+ */
+ void (*run)(const br_block_cbcdec_class *const *ctx,
+ void *iv, void *data, size_t len);
+};
+
+/**
+ * \brief Class type for CTR encryption/decryption implementations.
+ *
+ * A `br_block_ctr_class` instance points to the functions implementing
+ * a specific block cipher, when used in CTR mode for encrypting or
+ * decrypting data.
+ */
+typedef struct br_block_ctr_class_ br_block_ctr_class;
+struct br_block_ctr_class_ {
+ /**
+ * \brief Size (in bytes) of the context structure appropriate
+ * for containing subkeys.
+ */
+ size_t context_size;
+
+ /**
+ * \brief Size of individual blocks (in bytes).
+ */
+ unsigned block_size;
+
+ /**
+ * \brief Base-2 logarithm of the size of individual blocks,
+ * expressed in bytes.
+ */
+ unsigned log_block_size;
+
+ /**
+ * \brief Initialisation function.
+ *
+ * This function sets the `vtable` field in the context structure.
+ * The key length MUST be one of the key lengths supported by
+ * the implementation.
+ *
+ * \param ctx context structure to initialise.
+ * \param key secret key.
+ * \param key_len key length (in bytes).
+ */
+ void (*init)(const br_block_ctr_class **ctx,
+ const void *key, size_t key_len);
+
+ /**
+ * \brief Run the CTR encryption or decryption.
+ *
+ * The `iv` parameter points to the IV for this run; its
+ * length is exactly 4 bytes less than the block size (e.g.
+ * 12 bytes for AES/CTR). The IV is combined with a 32-bit
+ * block counter to produce the block value which is processed
+ * with the block cipher.
+ *
+ * The data to encrypt or decrypt is updated "in place". Its
+ * length (`len` bytes) is not required to be a multiple of
+ * the block size; if the final block is partial, then the
+ * corresponding key stream bits are dropped.
+ *
+ * The resulting counter value is returned.
+ *
+ * \param ctx context structure (already initialised).
+ * \param iv IV for CTR encryption/decryption.
+ * \param cc initial value for the block counter.
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ * \return the new block counter value.
+ */
+ uint32_t (*run)(const br_block_ctr_class *const *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len);
+};
+
+/**
+ * \brief Class type for combined CTR and CBC-MAC implementations.
+ *
+ * A `br_block_ctrcbc_class` instance points to the functions implementing
+ * a specific block cipher, when used in CTR mode for encrypting or
+ * decrypting data, along with CBC-MAC.
+ */
+typedef struct br_block_ctrcbc_class_ br_block_ctrcbc_class;
+struct br_block_ctrcbc_class_ {
+ /**
+ * \brief Size (in bytes) of the context structure appropriate
+ * for containing subkeys.
+ */
+ size_t context_size;
+
+ /**
+ * \brief Size of individual blocks (in bytes).
+ */
+ unsigned block_size;
+
+ /**
+ * \brief Base-2 logarithm of the size of individual blocks,
+ * expressed in bytes.
+ */
+ unsigned log_block_size;
+
+ /**
+ * \brief Initialisation function.
+ *
+ * This function sets the `vtable` field in the context structure.
+ * The key length MUST be one of the key lengths supported by
+ * the implementation.
+ *
+ * \param ctx context structure to initialise.
+ * \param key secret key.
+ * \param key_len key length (in bytes).
+ */
+ void (*init)(const br_block_ctrcbc_class **ctx,
+ const void *key, size_t key_len);
+
+ /**
+ * \brief Run the CTR encryption + CBC-MAC.
+ *
+ * The `ctr` parameter points to the counter; its length shall
+ * be equal to the block size. It is updated by this function
+ * as encryption proceeds.
+ *
+ * The `cbcmac` parameter points to the IV for CBC-MAC. The MAC
+ * is computed over the encrypted data (output of CTR
+ * encryption). Its length shall be equal to the block size. The
+ * computed CBC-MAC value is written over the `cbcmac` array.
+ *
+ * The data to encrypt is updated "in place". Its length (`len`
+ * bytes) MUST be a multiple of the block size.
+ *
+ * \param ctx context structure (already initialised).
+ * \param ctr counter for CTR encryption (initial and final).
+ * \param cbcmac IV and output buffer for CBC-MAC.
+ * \param data data to encrypt.
+ * \param len data length (in bytes).
+ */
+ void (*encrypt)(const br_block_ctrcbc_class *const *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+ /**
+ * \brief Run the CTR decryption + CBC-MAC.
+ *
+ * The `ctr` parameter points to the counter; its length shall
+ * be equal to the block size. It is updated by this function
+ * as decryption proceeds.
+ *
+ * The `cbcmac` parameter points to the IV for CBC-MAC. The MAC
+ * is computed over the encrypted data (i.e. before CTR
+ * decryption). Its length shall be equal to the block size. The
+ * computed CBC-MAC value is written over the `cbcmac` array.
+ *
+ * The data to decrypt is updated "in place". Its length (`len`
+ * bytes) MUST be a multiple of the block size.
+ *
+ * \param ctx context structure (already initialised).
+ * \param ctr counter for CTR encryption (initial and final).
+ * \param cbcmac IV and output buffer for CBC-MAC.
+ * \param data data to decrypt.
+ * \param len data length (in bytes).
+ */
+ void (*decrypt)(const br_block_ctrcbc_class *const *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+ /**
+ * \brief Run the CTR encryption/decryption only.
+ *
+ * The `ctr` parameter points to the counter; its length shall
+ * be equal to the block size. It is updated by this function
+ * as decryption proceeds.
+ *
+ * The data to decrypt is updated "in place". Its length (`len`
+ * bytes) MUST be a multiple of the block size.
+ *
+ * \param ctx context structure (already initialised).
+ * \param ctr counter for CTR encryption (initial and final).
+ * \param data data to decrypt.
+ * \param len data length (in bytes).
+ */
+ void (*ctr)(const br_block_ctrcbc_class *const *ctx,
+ void *ctr, void *data, size_t len);
+
+ /**
+ * \brief Run the CBC-MAC only.
+ *
+ * The `cbcmac` parameter points to the IV for CBC-MAC. The MAC
+ * is computed over the encrypted data (i.e. before CTR
+ * decryption). Its length shall be equal to the block size. The
+ * computed CBC-MAC value is written over the `cbcmac` array.
+ *
+ * The data is unmodified. Its length (`len` bytes) MUST be a
+ * multiple of the block size.
+ *
+ * \param ctx context structure (already initialised).
+ * \param cbcmac IV and output buffer for CBC-MAC.
+ * \param data data to decrypt.
+ * \param len data length (in bytes).
+ */
+ void (*mac)(const br_block_ctrcbc_class *const *ctx,
+ void *cbcmac, const void *data, size_t len);
+};
+
+/*
+ * Traditional, table-based AES implementation. It is fast, but uses
+ * internal tables (in particular a 1 kB table for encryption, another
+ * 1 kB table for decryption, and a 256-byte table for key schedule),
+ * and it is not constant-time. In contexts where cache-timing attacks
+ * apply, this implementation may leak the secret key.
+ */
+
+/** \brief AES block size (16 bytes). */
+#define br_aes_big_BLOCK_SIZE 16
+
+/**
+ * \brief Context for AES subkeys (`aes_big` implementation, CBC encryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcenc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_big_cbcenc_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_big` implementation, CBC decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcdec_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_big_cbcdec_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_big` implementation, CTR encryption
+ * and decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctr_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_big_ctr_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_big` implementation, CTR encryption
+ * and decryption + CBC-MAC).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctrcbc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_big_ctrcbc_keys;
+
+/**
+ * \brief Class instance for AES CBC encryption (`aes_big` implementation).
+ */
+extern const br_block_cbcenc_class br_aes_big_cbcenc_vtable;
+
+/**
+ * \brief Class instance for AES CBC decryption (`aes_big` implementation).
+ */
+extern const br_block_cbcdec_class br_aes_big_cbcdec_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption and decryption
+ * (`aes_big` implementation).
+ */
+extern const br_block_ctr_class br_aes_big_ctr_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption/decryption + CBC-MAC
+ * (`aes_big` implementation).
+ */
+extern const br_block_ctrcbc_class br_aes_big_ctrcbc_vtable;
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC encryption
+ * (`aes_big` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_big_cbcenc_init(br_aes_big_cbcenc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC decryption
+ * (`aes_big` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_big_cbcdec_init(br_aes_big_cbcdec_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR encryption
+ * and decryption (`aes_big` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_big_ctr_init(br_aes_big_ctr_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC
+ * (`aes_big` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_big_ctrcbc_init(br_aes_big_ctrcbc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief CBC encryption with AES (`aes_big` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_big_cbcenc_run(const br_aes_big_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CBC decryption with AES (`aes_big` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_big_cbcdec_run(const br_aes_big_cbcdec_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CTR encryption and decryption with AES (`aes_big` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (constant, 12 bytes).
+ * \param cc initial block counter value.
+ * \param data data to encrypt or decrypt (updated).
+ * \param len data length (in bytes).
+ * \return new block counter value.
+ */
+uint32_t br_aes_big_ctr_run(const br_aes_big_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len);
+
+/**
+ * \brief CTR encryption + CBC-MAC with AES (`aes_big` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_big_ctrcbc_encrypt(const br_aes_big_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR decryption + CBC-MAC with AES (`aes_big` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_big_ctrcbc_decrypt(const br_aes_big_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR encryption/decryption with AES (`aes_big` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param data data to MAC (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_big_ctrcbc_ctr(const br_aes_big_ctrcbc_keys *ctx,
+ void *ctr, void *data, size_t len);
+
+/**
+ * \brief CBC-MAC with AES (`aes_big` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to MAC (unmodified).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_big_ctrcbc_mac(const br_aes_big_ctrcbc_keys *ctx,
+ void *cbcmac, const void *data, size_t len);
+
+/*
+ * AES implementation optimized for size. It is slower than the
+ * traditional table-based AES implementation, but requires much less
+ * code. It still uses data-dependent table accesses (albeit within a
+ * much smaller 256-byte table), which makes it conceptually vulnerable
+ * to cache-timing attacks.
+ */
+
+/** \brief AES block size (16 bytes). */
+#define br_aes_small_BLOCK_SIZE 16
+
+/**
+ * \brief Context for AES subkeys (`aes_small` implementation, CBC encryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcenc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_small_cbcenc_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_small` implementation, CBC decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcdec_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_small_cbcdec_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_small` implementation, CTR encryption
+ * and decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctr_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_small_ctr_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_small` implementation, CTR encryption
+ * and decryption + CBC-MAC).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctrcbc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_small_ctrcbc_keys;
+
+/**
+ * \brief Class instance for AES CBC encryption (`aes_small` implementation).
+ */
+extern const br_block_cbcenc_class br_aes_small_cbcenc_vtable;
+
+/**
+ * \brief Class instance for AES CBC decryption (`aes_small` implementation).
+ */
+extern const br_block_cbcdec_class br_aes_small_cbcdec_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption and decryption
+ * (`aes_small` implementation).
+ */
+extern const br_block_ctr_class br_aes_small_ctr_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption/decryption + CBC-MAC
+ * (`aes_small` implementation).
+ */
+extern const br_block_ctrcbc_class br_aes_small_ctrcbc_vtable;
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC encryption
+ * (`aes_small` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_small_cbcenc_init(br_aes_small_cbcenc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC decryption
+ * (`aes_small` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_small_cbcdec_init(br_aes_small_cbcdec_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR encryption
+ * and decryption (`aes_small` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_small_ctr_init(br_aes_small_ctr_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC
+ * (`aes_small` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_small_ctrcbc_init(br_aes_small_ctrcbc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief CBC encryption with AES (`aes_small` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_small_cbcenc_run(const br_aes_small_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CBC decryption with AES (`aes_small` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_small_cbcdec_run(const br_aes_small_cbcdec_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CTR encryption and decryption with AES (`aes_small` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (constant, 12 bytes).
+ * \param cc initial block counter value.
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes).
+ * \return new block counter value.
+ */
+uint32_t br_aes_small_ctr_run(const br_aes_small_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len);
+
+/**
+ * \brief CTR encryption + CBC-MAC with AES (`aes_small` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_small_ctrcbc_encrypt(const br_aes_small_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR decryption + CBC-MAC with AES (`aes_small` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_small_ctrcbc_decrypt(const br_aes_small_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR encryption/decryption with AES (`aes_small` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param data data to MAC (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_small_ctrcbc_ctr(const br_aes_small_ctrcbc_keys *ctx,
+ void *ctr, void *data, size_t len);
+
+/**
+ * \brief CBC-MAC with AES (`aes_small` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to MAC (unmodified).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_small_ctrcbc_mac(const br_aes_small_ctrcbc_keys *ctx,
+ void *cbcmac, const void *data, size_t len);
+
+/*
+ * Constant-time AES implementation. Its size is similar to that of
+ * 'aes_big', and its performance is similar to that of 'aes_small' (faster
+ * decryption, slower encryption). However, it is constant-time, i.e.
+ * immune to cache-timing and similar attacks.
+ */
+
+/** \brief AES block size (16 bytes). */
+#define br_aes_ct_BLOCK_SIZE 16
+
+/**
+ * \brief Context for AES subkeys (`aes_ct` implementation, CBC encryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcenc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_ct_cbcenc_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_ct` implementation, CBC decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcdec_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_ct_cbcdec_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_ct` implementation, CTR encryption
+ * and decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctr_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_ct_ctr_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_ct` implementation, CTR encryption
+ * and decryption + CBC-MAC).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctrcbc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_ct_ctrcbc_keys;
+
+/**
+ * \brief Class instance for AES CBC encryption (`aes_ct` implementation).
+ */
+extern const br_block_cbcenc_class br_aes_ct_cbcenc_vtable;
+
+/**
+ * \brief Class instance for AES CBC decryption (`aes_ct` implementation).
+ */
+extern const br_block_cbcdec_class br_aes_ct_cbcdec_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption and decryption
+ * (`aes_ct` implementation).
+ */
+extern const br_block_ctr_class br_aes_ct_ctr_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption/decryption + CBC-MAC
+ * (`aes_ct` implementation).
+ */
+extern const br_block_ctrcbc_class br_aes_ct_ctrcbc_vtable;
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC encryption
+ * (`aes_ct` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_ct_cbcenc_init(br_aes_ct_cbcenc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC decryption
+ * (`aes_ct` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_ct_cbcdec_init(br_aes_ct_cbcdec_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR encryption
+ * and decryption (`aes_ct` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_ct_ctr_init(br_aes_ct_ctr_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC
+ * (`aes_ct` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_ct_ctrcbc_init(br_aes_ct_ctrcbc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief CBC encryption with AES (`aes_ct` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_ct_cbcenc_run(const br_aes_ct_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CBC decryption with AES (`aes_ct` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_ct_cbcdec_run(const br_aes_ct_cbcdec_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CTR encryption and decryption with AES (`aes_ct` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (constant, 12 bytes).
+ * \param cc initial block counter value.
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes).
+ * \return new block counter value.
+ */
+uint32_t br_aes_ct_ctr_run(const br_aes_ct_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len);
+
+/**
+ * \brief CTR encryption + CBC-MAC with AES (`aes_ct` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_ct_ctrcbc_encrypt(const br_aes_ct_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR decryption + CBC-MAC with AES (`aes_ct` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_ct_ctrcbc_decrypt(const br_aes_ct_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR encryption/decryption with AES (`aes_ct` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param data data to MAC (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_ct_ctrcbc_ctr(const br_aes_ct_ctrcbc_keys *ctx,
+ void *ctr, void *data, size_t len);
+
+/**
+ * \brief CBC-MAC with AES (`aes_ct` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to MAC (unmodified).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_ct_ctrcbc_mac(const br_aes_ct_ctrcbc_keys *ctx,
+ void *cbcmac, const void *data, size_t len);
+
+/*
+ * 64-bit constant-time AES implementation. It is similar to 'aes_ct'
+ * but uses 64-bit registers, making it about twice faster than 'aes_ct'
+ * on 64-bit platforms, while remaining constant-time and with a similar
+ * code size. (The doubling in performance is only for CBC decryption
+ * and CTR mode; CBC encryption is non-parallel and cannot benefit from
+ * the larger registers.)
+ */
+
+/** \brief AES block size (16 bytes). */
+#define br_aes_ct64_BLOCK_SIZE 16
+
+/**
+ * \brief Context for AES subkeys (`aes_ct64` implementation, CBC encryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcenc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint64_t skey[30];
+ unsigned num_rounds;
+#endif
+} br_aes_ct64_cbcenc_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_ct64` implementation, CBC decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcdec_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint64_t skey[30];
+ unsigned num_rounds;
+#endif
+} br_aes_ct64_cbcdec_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_ct64` implementation, CTR encryption
+ * and decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctr_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint64_t skey[30];
+ unsigned num_rounds;
+#endif
+} br_aes_ct64_ctr_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_ct64` implementation, CTR encryption
+ * and decryption + CBC-MAC).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctrcbc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint64_t skey[30];
+ unsigned num_rounds;
+#endif
+} br_aes_ct64_ctrcbc_keys;
+
+/**
+ * \brief Class instance for AES CBC encryption (`aes_ct64` implementation).
+ */
+extern const br_block_cbcenc_class br_aes_ct64_cbcenc_vtable;
+
+/**
+ * \brief Class instance for AES CBC decryption (`aes_ct64` implementation).
+ */
+extern const br_block_cbcdec_class br_aes_ct64_cbcdec_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption and decryption
+ * (`aes_ct64` implementation).
+ */
+extern const br_block_ctr_class br_aes_ct64_ctr_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption/decryption + CBC-MAC
+ * (`aes_ct64` implementation).
+ */
+extern const br_block_ctrcbc_class br_aes_ct64_ctrcbc_vtable;
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC encryption
+ * (`aes_ct64` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_ct64_cbcenc_init(br_aes_ct64_cbcenc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC decryption
+ * (`aes_ct64` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_ct64_cbcdec_init(br_aes_ct64_cbcdec_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR encryption
+ * and decryption (`aes_ct64` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_ct64_ctr_init(br_aes_ct64_ctr_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC
+ * (`aes_ct64` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_ct64_ctrcbc_init(br_aes_ct64_ctrcbc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief CBC encryption with AES (`aes_ct64` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_ct64_cbcenc_run(const br_aes_ct64_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CBC decryption with AES (`aes_ct64` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_ct64_cbcdec_run(const br_aes_ct64_cbcdec_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CTR encryption and decryption with AES (`aes_ct64` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (constant, 12 bytes).
+ * \param cc initial block counter value.
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes).
+ * \return new block counter value.
+ */
+uint32_t br_aes_ct64_ctr_run(const br_aes_ct64_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len);
+
+/**
+ * \brief CTR encryption + CBC-MAC with AES (`aes_ct64` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_ct64_ctrcbc_encrypt(const br_aes_ct64_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR decryption + CBC-MAC with AES (`aes_ct64` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_ct64_ctrcbc_decrypt(const br_aes_ct64_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR encryption/decryption with AES (`aes_ct64` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param data data to MAC (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_ct64_ctrcbc_ctr(const br_aes_ct64_ctrcbc_keys *ctx,
+ void *ctr, void *data, size_t len);
+
+/**
+ * \brief CBC-MAC with AES (`aes_ct64` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to MAC (unmodified).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_ct64_ctrcbc_mac(const br_aes_ct64_ctrcbc_keys *ctx,
+ void *cbcmac, const void *data, size_t len);
+
+/*
+ * AES implementation using AES-NI opcodes (x86 platform).
+ */
+
+/** \brief AES block size (16 bytes). */
+#define br_aes_x86ni_BLOCK_SIZE 16
+
+/**
+ * \brief Context for AES subkeys (`aes_x86ni` implementation, CBC encryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcenc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ union {
+ unsigned char skni[16 * 15];
+ } skey;
+ unsigned num_rounds;
+#endif
+} br_aes_x86ni_cbcenc_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_x86ni` implementation, CBC decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcdec_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ union {
+ unsigned char skni[16 * 15];
+ } skey;
+ unsigned num_rounds;
+#endif
+} br_aes_x86ni_cbcdec_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_x86ni` implementation, CTR encryption
+ * and decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctr_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ union {
+ unsigned char skni[16 * 15];
+ } skey;
+ unsigned num_rounds;
+#endif
+} br_aes_x86ni_ctr_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_x86ni` implementation, CTR encryption
+ * and decryption + CBC-MAC).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctrcbc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ union {
+ unsigned char skni[16 * 15];
+ } skey;
+ unsigned num_rounds;
+#endif
+} br_aes_x86ni_ctrcbc_keys;
+
+/**
+ * \brief Class instance for AES CBC encryption (`aes_x86ni` implementation).
+ *
+ * Since this implementation might be omitted from the library, or the
+ * AES opcode unavailable on the current CPU, a pointer to this class
+ * instance should be obtained through `br_aes_x86ni_cbcenc_get_vtable()`.
+ */
+extern const br_block_cbcenc_class br_aes_x86ni_cbcenc_vtable;
+
+/**
+ * \brief Class instance for AES CBC decryption (`aes_x86ni` implementation).
+ *
+ * Since this implementation might be omitted from the library, or the
+ * AES opcode unavailable on the current CPU, a pointer to this class
+ * instance should be obtained through `br_aes_x86ni_cbcdec_get_vtable()`.
+ */
+extern const br_block_cbcdec_class br_aes_x86ni_cbcdec_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption and decryption
+ * (`aes_x86ni` implementation).
+ *
+ * Since this implementation might be omitted from the library, or the
+ * AES opcode unavailable on the current CPU, a pointer to this class
+ * instance should be obtained through `br_aes_x86ni_ctr_get_vtable()`.
+ */
+extern const br_block_ctr_class br_aes_x86ni_ctr_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption/decryption + CBC-MAC
+ * (`aes_x86ni` implementation).
+ *
+ * Since this implementation might be omitted from the library, or the
+ * AES opcode unavailable on the current CPU, a pointer to this class
+ * instance should be obtained through `br_aes_x86ni_ctrcbc_get_vtable()`.
+ */
+extern const br_block_ctrcbc_class br_aes_x86ni_ctrcbc_vtable;
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC encryption
+ * (`aes_x86ni` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_x86ni_cbcenc_init(br_aes_x86ni_cbcenc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC decryption
+ * (`aes_x86ni` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_x86ni_cbcdec_init(br_aes_x86ni_cbcdec_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR encryption
+ * and decryption (`aes_x86ni` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_x86ni_ctr_init(br_aes_x86ni_ctr_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC
+ * (`aes_x86ni` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_x86ni_ctrcbc_init(br_aes_x86ni_ctrcbc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief CBC encryption with AES (`aes_x86ni` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_x86ni_cbcenc_run(const br_aes_x86ni_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CBC decryption with AES (`aes_x86ni` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_x86ni_cbcdec_run(const br_aes_x86ni_cbcdec_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CTR encryption and decryption with AES (`aes_x86ni` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (constant, 12 bytes).
+ * \param cc initial block counter value.
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes).
+ * \return new block counter value.
+ */
+uint32_t br_aes_x86ni_ctr_run(const br_aes_x86ni_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len);
+
+/**
+ * \brief CTR encryption + CBC-MAC with AES (`aes_x86ni` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_x86ni_ctrcbc_encrypt(const br_aes_x86ni_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR decryption + CBC-MAC with AES (`aes_x86ni` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_x86ni_ctrcbc_decrypt(const br_aes_x86ni_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR encryption/decryption with AES (`aes_x86ni` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param data data to MAC (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_x86ni_ctrcbc_ctr(const br_aes_x86ni_ctrcbc_keys *ctx,
+ void *ctr, void *data, size_t len);
+
+/**
+ * \brief CBC-MAC with AES (`aes_x86ni` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to MAC (unmodified).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_x86ni_ctrcbc_mac(const br_aes_x86ni_ctrcbc_keys *ctx,
+ void *cbcmac, const void *data, size_t len);
+
+/**
+ * \brief Obtain the `aes_x86ni` AES-CBC (encryption) implementation, if
+ * available.
+ *
+ * This function returns a pointer to `br_aes_x86ni_cbcenc_vtable`, if
+ * that implementation was compiled in the library _and_ the x86 AES
+ * opcodes are available on the currently running CPU. If either of
+ * these conditions is not met, then this function returns `NULL`.
+ *
+ * \return the `aes_x86ni` AES-CBC (encryption) implementation, or `NULL`.
+ */
+const br_block_cbcenc_class *br_aes_x86ni_cbcenc_get_vtable(void);
+
+/**
+ * \brief Obtain the `aes_x86ni` AES-CBC (decryption) implementation, if
+ * available.
+ *
+ * This function returns a pointer to `br_aes_x86ni_cbcdec_vtable`, if
+ * that implementation was compiled in the library _and_ the x86 AES
+ * opcodes are available on the currently running CPU. If either of
+ * these conditions is not met, then this function returns `NULL`.
+ *
+ * \return the `aes_x86ni` AES-CBC (decryption) implementation, or `NULL`.
+ */
+const br_block_cbcdec_class *br_aes_x86ni_cbcdec_get_vtable(void);
+
+/**
+ * \brief Obtain the `aes_x86ni` AES-CTR implementation, if available.
+ *
+ * This function returns a pointer to `br_aes_x86ni_ctr_vtable`, if
+ * that implementation was compiled in the library _and_ the x86 AES
+ * opcodes are available on the currently running CPU. If either of
+ * these conditions is not met, then this function returns `NULL`.
+ *
+ * \return the `aes_x86ni` AES-CTR implementation, or `NULL`.
+ */
+const br_block_ctr_class *br_aes_x86ni_ctr_get_vtable(void);
+
+/**
+ * \brief Obtain the `aes_x86ni` AES-CTR + CBC-MAC implementation, if
+ * available.
+ *
+ * This function returns a pointer to `br_aes_x86ni_ctrcbc_vtable`, if
+ * that implementation was compiled in the library _and_ the x86 AES
+ * opcodes are available on the currently running CPU. If either of
+ * these conditions is not met, then this function returns `NULL`.
+ *
+ * \return the `aes_x86ni` AES-CTR implementation, or `NULL`.
+ */
+const br_block_ctrcbc_class *br_aes_x86ni_ctrcbc_get_vtable(void);
+
+/*
+ * AES implementation using POWER8 opcodes.
+ */
+
+/** \brief AES block size (16 bytes). */
+#define br_aes_pwr8_BLOCK_SIZE 16
+
+/**
+ * \brief Context for AES subkeys (`aes_pwr8` implementation, CBC encryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcenc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ union {
+ unsigned char skni[16 * 15];
+ } skey;
+ unsigned num_rounds;
+#endif
+} br_aes_pwr8_cbcenc_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_pwr8` implementation, CBC decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcdec_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ union {
+ unsigned char skni[16 * 15];
+ } skey;
+ unsigned num_rounds;
+#endif
+} br_aes_pwr8_cbcdec_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_pwr8` implementation, CTR encryption
+ * and decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctr_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ union {
+ unsigned char skni[16 * 15];
+ } skey;
+ unsigned num_rounds;
+#endif
+} br_aes_pwr8_ctr_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_pwr8` implementation, CTR encryption
+ * and decryption + CBC-MAC).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctrcbc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ union {
+ unsigned char skni[16 * 15];
+ } skey;
+ unsigned num_rounds;
+#endif
+} br_aes_pwr8_ctrcbc_keys;
+
+/**
+ * \brief Class instance for AES CBC encryption (`aes_pwr8` implementation).
+ *
+ * Since this implementation might be omitted from the library, or the
+ * AES opcode unavailable on the current CPU, a pointer to this class
+ * instance should be obtained through `br_aes_pwr8_cbcenc_get_vtable()`.
+ */
+extern const br_block_cbcenc_class br_aes_pwr8_cbcenc_vtable;
+
+/**
+ * \brief Class instance for AES CBC decryption (`aes_pwr8` implementation).
+ *
+ * Since this implementation might be omitted from the library, or the
+ * AES opcode unavailable on the current CPU, a pointer to this class
+ * instance should be obtained through `br_aes_pwr8_cbcdec_get_vtable()`.
+ */
+extern const br_block_cbcdec_class br_aes_pwr8_cbcdec_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption and decryption
+ * (`aes_pwr8` implementation).
+ *
+ * Since this implementation might be omitted from the library, or the
+ * AES opcode unavailable on the current CPU, a pointer to this class
+ * instance should be obtained through `br_aes_pwr8_ctr_get_vtable()`.
+ */
+extern const br_block_ctr_class br_aes_pwr8_ctr_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption/decryption + CBC-MAC
+ * (`aes_pwr8` implementation).
+ *
+ * Since this implementation might be omitted from the library, or the
+ * AES opcode unavailable on the current CPU, a pointer to this class
+ * instance should be obtained through `br_aes_pwr8_ctrcbc_get_vtable()`.
+ */
+extern const br_block_ctrcbc_class br_aes_pwr8_ctrcbc_vtable;
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC encryption
+ * (`aes_pwr8` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_pwr8_cbcenc_init(br_aes_pwr8_cbcenc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC decryption
+ * (`aes_pwr8` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_pwr8_cbcdec_init(br_aes_pwr8_cbcdec_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR encryption
+ * and decryption (`aes_pwr8` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_pwr8_ctr_init(br_aes_pwr8_ctr_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC
+ * (`aes_pwr8` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_pwr8_ctrcbc_init(br_aes_pwr8_ctrcbc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief CBC encryption with AES (`aes_pwr8` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_pwr8_cbcenc_run(const br_aes_pwr8_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CBC decryption with AES (`aes_pwr8` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_pwr8_cbcdec_run(const br_aes_pwr8_cbcdec_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CTR encryption and decryption with AES (`aes_pwr8` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (constant, 12 bytes).
+ * \param cc initial block counter value.
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes).
+ * \return new block counter value.
+ */
+uint32_t br_aes_pwr8_ctr_run(const br_aes_pwr8_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len);
+
+/**
+ * \brief CTR encryption + CBC-MAC with AES (`aes_pwr8` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_pwr8_ctrcbc_encrypt(const br_aes_pwr8_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR decryption + CBC-MAC with AES (`aes_pwr8` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_pwr8_ctrcbc_decrypt(const br_aes_pwr8_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR encryption/decryption with AES (`aes_pwr8` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param data data to MAC (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_pwr8_ctrcbc_ctr(const br_aes_pwr8_ctrcbc_keys *ctx,
+ void *ctr, void *data, size_t len);
+
+/**
+ * \brief CBC-MAC with AES (`aes_pwr8` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to MAC (unmodified).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_pwr8_ctrcbc_mac(const br_aes_pwr8_ctrcbc_keys *ctx,
+ void *cbcmac, const void *data, size_t len);
+
+/**
+ * \brief Obtain the `aes_pwr8` AES-CBC (encryption) implementation, if
+ * available.
+ *
+ * This function returns a pointer to `br_aes_pwr8_cbcenc_vtable`, if
+ * that implementation was compiled in the library _and_ the POWER8
+ * crypto opcodes are available on the currently running CPU. If either
+ * of these conditions is not met, then this function returns `NULL`.
+ *
+ * \return the `aes_pwr8` AES-CBC (encryption) implementation, or `NULL`.
+ */
+const br_block_cbcenc_class *br_aes_pwr8_cbcenc_get_vtable(void);
+
+/**
+ * \brief Obtain the `aes_pwr8` AES-CBC (decryption) implementation, if
+ * available.
+ *
+ * This function returns a pointer to `br_aes_pwr8_cbcdec_vtable`, if
+ * that implementation was compiled in the library _and_ the POWER8
+ * crypto opcodes are available on the currently running CPU. If either
+ * of these conditions is not met, then this function returns `NULL`.
+ *
+ * \return the `aes_pwr8` AES-CBC (decryption) implementation, or `NULL`.
+ */
+const br_block_cbcdec_class *br_aes_pwr8_cbcdec_get_vtable(void);
+
+/**
+ * \brief Obtain the `aes_pwr8` AES-CTR implementation, if available.
+ *
+ * This function returns a pointer to `br_aes_pwr8_ctr_vtable`, if that
+ * implementation was compiled in the library _and_ the POWER8 crypto
+ * opcodes are available on the currently running CPU. If either of
+ * these conditions is not met, then this function returns `NULL`.
+ *
+ * \return the `aes_pwr8` AES-CTR implementation, or `NULL`.
+ */
+const br_block_ctr_class *br_aes_pwr8_ctr_get_vtable(void);
+
+/**
+ * \brief Obtain the `aes_pwr8` AES-CTR + CBC-MAC implementation, if
+ * available.
+ *
+ * This function returns a pointer to `br_aes_pwr8_ctrcbc_vtable`, if
+ * that implementation was compiled in the library _and_ the POWER8 AES
+ * opcodes are available on the currently running CPU. If either of
+ * these conditions is not met, then this function returns `NULL`.
+ *
+ * \return the `aes_pwr8` AES-CTR implementation, or `NULL`.
+ */
+const br_block_ctrcbc_class *br_aes_pwr8_ctrcbc_get_vtable(void);
+
+/**
+ * \brief Aggregate structure large enough to be used as context for
+ * subkeys (CBC encryption) for all AES implementations.
+ */
+typedef union {
+ const br_block_cbcenc_class *vtable;
+ br_aes_big_cbcenc_keys c_big;
+ br_aes_small_cbcenc_keys c_small;
+ br_aes_ct_cbcenc_keys c_ct;
+ br_aes_ct64_cbcenc_keys c_ct64;
+ br_aes_x86ni_cbcenc_keys c_x86ni;
+ br_aes_pwr8_cbcenc_keys c_pwr8;
+} br_aes_gen_cbcenc_keys;
+
+/**
+ * \brief Aggregate structure large enough to be used as context for
+ * subkeys (CBC decryption) for all AES implementations.
+ */
+typedef union {
+ const br_block_cbcdec_class *vtable;
+ br_aes_big_cbcdec_keys c_big;
+ br_aes_small_cbcdec_keys c_small;
+ br_aes_ct_cbcdec_keys c_ct;
+ br_aes_ct64_cbcdec_keys c_ct64;
+ br_aes_x86ni_cbcdec_keys c_x86ni;
+ br_aes_pwr8_cbcdec_keys c_pwr8;
+} br_aes_gen_cbcdec_keys;
+
+/**
+ * \brief Aggregate structure large enough to be used as context for
+ * subkeys (CTR encryption and decryption) for all AES implementations.
+ */
+typedef union {
+ const br_block_ctr_class *vtable;
+ br_aes_big_ctr_keys c_big;
+ br_aes_small_ctr_keys c_small;
+ br_aes_ct_ctr_keys c_ct;
+ br_aes_ct64_ctr_keys c_ct64;
+ br_aes_x86ni_ctr_keys c_x86ni;
+ br_aes_pwr8_ctr_keys c_pwr8;
+} br_aes_gen_ctr_keys;
+
+/**
+ * \brief Aggregate structure large enough to be used as context for
+ * subkeys (CTR encryption/decryption + CBC-MAC) for all AES implementations.
+ */
+typedef union {
+ const br_block_ctrcbc_class *vtable;
+ br_aes_big_ctrcbc_keys c_big;
+ br_aes_small_ctrcbc_keys c_small;
+ br_aes_ct_ctrcbc_keys c_ct;
+ br_aes_ct64_ctrcbc_keys c_ct64;
+ br_aes_x86ni_ctrcbc_keys c_x86ni;
+ br_aes_pwr8_ctrcbc_keys c_pwr8;
+} br_aes_gen_ctrcbc_keys;
+
+/*
+ * Traditional, table-based implementation for DES/3DES. Since tables are
+ * used, cache-timing attacks are conceptually possible.
+ */
+
+/** \brief DES/3DES block size (8 bytes). */
+#define br_des_tab_BLOCK_SIZE 8
+
+/**
+ * \brief Context for DES subkeys (`des_tab` implementation, CBC encryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcenc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[96];
+ unsigned num_rounds;
+#endif
+} br_des_tab_cbcenc_keys;
+
+/**
+ * \brief Context for DES subkeys (`des_tab` implementation, CBC decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcdec_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[96];
+ unsigned num_rounds;
+#endif
+} br_des_tab_cbcdec_keys;
+
+/**
+ * \brief Class instance for DES CBC encryption (`des_tab` implementation).
+ */
+extern const br_block_cbcenc_class br_des_tab_cbcenc_vtable;
+
+/**
+ * \brief Class instance for DES CBC decryption (`des_tab` implementation).
+ */
+extern const br_block_cbcdec_class br_des_tab_cbcdec_vtable;
+
+/**
+ * \brief Context initialisation (key schedule) for DES CBC encryption
+ * (`des_tab` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_des_tab_cbcenc_init(br_des_tab_cbcenc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for DES CBC decryption
+ * (`des_tab` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_des_tab_cbcdec_init(br_des_tab_cbcdec_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief CBC encryption with DES (`des_tab` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 8).
+ */
+void br_des_tab_cbcenc_run(const br_des_tab_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CBC decryption with DES (`des_tab` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 8).
+ */
+void br_des_tab_cbcdec_run(const br_des_tab_cbcdec_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/*
+ * Constant-time implementation for DES/3DES. It is substantially slower
+ * (by a factor of about 4x), but also immune to cache-timing attacks.
+ */
+
+/** \brief DES/3DES block size (8 bytes). */
+#define br_des_ct_BLOCK_SIZE 8
+
+/**
+ * \brief Context for DES subkeys (`des_ct` implementation, CBC encryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcenc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[96];
+ unsigned num_rounds;
+#endif
+} br_des_ct_cbcenc_keys;
+
+/**
+ * \brief Context for DES subkeys (`des_ct` implementation, CBC decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcdec_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[96];
+ unsigned num_rounds;
+#endif
+} br_des_ct_cbcdec_keys;
+
+/**
+ * \brief Class instance for DES CBC encryption (`des_ct` implementation).
+ */
+extern const br_block_cbcenc_class br_des_ct_cbcenc_vtable;
+
+/**
+ * \brief Class instance for DES CBC decryption (`des_ct` implementation).
+ */
+extern const br_block_cbcdec_class br_des_ct_cbcdec_vtable;
+
+/**
+ * \brief Context initialisation (key schedule) for DES CBC encryption
+ * (`des_ct` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_des_ct_cbcenc_init(br_des_ct_cbcenc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for DES CBC decryption
+ * (`des_ct` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_des_ct_cbcdec_init(br_des_ct_cbcdec_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief CBC encryption with DES (`des_ct` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 8).
+ */
+void br_des_ct_cbcenc_run(const br_des_ct_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CBC decryption with DES (`des_ct` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 8).
+ */
+void br_des_ct_cbcdec_run(const br_des_ct_cbcdec_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/*
+ * These structures are large enough to accommodate subkeys for all
+ * DES/3DES implementations.
+ */
+
+/**
+ * \brief Aggregate structure large enough to be used as context for
+ * subkeys (CBC encryption) for all DES implementations.
+ */
+typedef union {
+ const br_block_cbcenc_class *vtable;
+ br_des_tab_cbcenc_keys tab;
+ br_des_ct_cbcenc_keys ct;
+} br_des_gen_cbcenc_keys;
+
+/**
+ * \brief Aggregate structure large enough to be used as context for
+ * subkeys (CBC decryption) for all DES implementations.
+ */
+typedef union {
+ const br_block_cbcdec_class *vtable;
+ br_des_tab_cbcdec_keys c_tab;
+ br_des_ct_cbcdec_keys c_ct;
+} br_des_gen_cbcdec_keys;
+
+/**
+ * \brief Type for a ChaCha20 implementation.
+ *
+ * An implementation follows the description in RFC 7539:
+ *
+ * - Key is 256 bits (`key` points to exactly 32 bytes).
+ *
+ * - IV is 96 bits (`iv` points to exactly 12 bytes).
+ *
+ * - Block counter is over 32 bits and starts at value `cc`; the
+ * resulting value is returned.
+ *
+ * Data (pointed to by `data`, of length `len`) is encrypted/decrypted
+ * in place. If `len` is not a multiple of 64, then the excess bytes from
+ * the last block processing are dropped (therefore, "chunked" processing
+ * works only as long as each non-final chunk has a length multiple of 64).
+ *
+ * \param key secret key (32 bytes).
+ * \param iv IV (12 bytes).
+ * \param cc initial counter value.
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ */
+typedef uint32_t (*br_chacha20_run)(const void *key,
+ const void *iv, uint32_t cc, void *data, size_t len);
+
+/**
+ * \brief ChaCha20 implementation (straightforward C code, constant-time).
+ *
+ * \see br_chacha20_run
+ *
+ * \param key secret key (32 bytes).
+ * \param iv IV (12 bytes).
+ * \param cc initial counter value.
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ */
+uint32_t br_chacha20_ct_run(const void *key,
+ const void *iv, uint32_t cc, void *data, size_t len);
+
+/**
+ * \brief ChaCha20 implementation (SSE2 code, constant-time).
+ *
+ * This implementation is available only on x86 platforms, depending on
+ * compiler support. Moreover, in 32-bit mode, it might not actually run,
+ * if the underlying hardware does not implement the SSE2 opcode (in
+ * 64-bit mode, SSE2 is part of the ABI, so if the code could be compiled
+ * at all, then it can run). Use `br_chacha20_sse2_get()` to safely obtain
+ * a pointer to that function.
+ *
+ * \see br_chacha20_run
+ *
+ * \param key secret key (32 bytes).
+ * \param iv IV (12 bytes).
+ * \param cc initial counter value.
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ */
+uint32_t br_chacha20_sse2_run(const void *key,
+ const void *iv, uint32_t cc, void *data, size_t len);
+
+/**
+ * \brief Obtain the `sse2` ChaCha20 implementation, if available.
+ *
+ * This function returns a pointer to `br_chacha20_sse2_run`, if
+ * that implementation was compiled in the library _and_ the SSE2
+ * opcodes are available on the currently running CPU. If either of
+ * these conditions is not met, then this function returns `0`.
+ *
+ * \return the `sse2` ChaCha20 implementation, or `0`.
+ */
+br_chacha20_run br_chacha20_sse2_get(void);
+
+/**
+ * \brief Type for a ChaCha20+Poly1305 AEAD implementation.
+ *
+ * The provided data is encrypted or decrypted with ChaCha20. The
+ * authentication tag is computed on the concatenation of the
+ * additional data and the ciphertext, with the padding and lengths
+ * as described in RFC 7539 (section 2.8).
+ *
+ * After decryption, the caller is responsible for checking that the
+ * computed tag matches the expected value.
+ *
+ * \param key secret key (32 bytes).
+ * \param iv nonce (12 bytes).
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ * \param aad additional authenticated data.
+ * \param aad_len length of additional authenticated data (in bytes).
+ * \param tag output buffer for the authentication tag.
+ * \param ichacha implementation of ChaCha20.
+ * \param encrypt non-zero for encryption, zero for decryption.
+ */
+typedef void (*br_poly1305_run)(const void *key, const void *iv,
+ void *data, size_t len, const void *aad, size_t aad_len,
+ void *tag, br_chacha20_run ichacha, int encrypt);
+
+/**
+ * \brief ChaCha20+Poly1305 AEAD implementation (mixed 32-bit multiplications).
+ *
+ * \see br_poly1305_run
+ *
+ * \param key secret key (32 bytes).
+ * \param iv nonce (12 bytes).
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ * \param aad additional authenticated data.
+ * \param aad_len length of additional authenticated data (in bytes).
+ * \param tag output buffer for the authentication tag.
+ * \param ichacha implementation of ChaCha20.
+ * \param encrypt non-zero for encryption, zero for decryption.
+ */
+void br_poly1305_ctmul_run(const void *key, const void *iv,
+ void *data, size_t len, const void *aad, size_t aad_len,
+ void *tag, br_chacha20_run ichacha, int encrypt);
+
+/**
+ * \brief ChaCha20+Poly1305 AEAD implementation (pure 32-bit multiplications).
+ *
+ * \see br_poly1305_run
+ *
+ * \param key secret key (32 bytes).
+ * \param iv nonce (12 bytes).
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ * \param aad additional authenticated data.
+ * \param aad_len length of additional authenticated data (in bytes).
+ * \param tag output buffer for the authentication tag.
+ * \param ichacha implementation of ChaCha20.
+ * \param encrypt non-zero for encryption, zero for decryption.
+ */
+void br_poly1305_ctmul32_run(const void *key, const void *iv,
+ void *data, size_t len, const void *aad, size_t aad_len,
+ void *tag, br_chacha20_run ichacha, int encrypt);
+
+/**
+ * \brief ChaCha20+Poly1305 AEAD implementation (i15).
+ *
+ * This implementation relies on the generic big integer code "i15"
+ * (which uses pure 32-bit multiplications). As such, it may save a
+ * little code footprint in a context where "i15" is already included
+ * (e.g. for elliptic curves or for RSA); however, it is also
+ * substantially slower than the ctmul and ctmul32 implementations.
+ *
+ * \see br_poly1305_run
+ *
+ * \param key secret key (32 bytes).
+ * \param iv nonce (12 bytes).
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ * \param aad additional authenticated data.
+ * \param aad_len length of additional authenticated data (in bytes).
+ * \param tag output buffer for the authentication tag.
+ * \param ichacha implementation of ChaCha20.
+ * \param encrypt non-zero for encryption, zero for decryption.
+ */
+void br_poly1305_i15_run(const void *key, const void *iv,
+ void *data, size_t len, const void *aad, size_t aad_len,
+ void *tag, br_chacha20_run ichacha, int encrypt);
+
+/**
+ * \brief ChaCha20+Poly1305 AEAD implementation (ctmulq).
+ *
+ * This implementation uses 64-bit multiplications (result over 128 bits).
+ * It is available only on platforms that offer such a primitive (in
+ * practice, 64-bit architectures). Use `br_poly1305_ctmulq_get()` to
+ * dynamically obtain a pointer to that function, or 0 if not supported.
+ *
+ * \see br_poly1305_run
+ *
+ * \param key secret key (32 bytes).
+ * \param iv nonce (12 bytes).
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ * \param aad additional authenticated data.
+ * \param aad_len length of additional authenticated data (in bytes).
+ * \param tag output buffer for the authentication tag.
+ * \param ichacha implementation of ChaCha20.
+ * \param encrypt non-zero for encryption, zero for decryption.
+ */
+void br_poly1305_ctmulq_run(const void *key, const void *iv,
+ void *data, size_t len, const void *aad, size_t aad_len,
+ void *tag, br_chacha20_run ichacha, int encrypt);
+
+/**
+ * \brief Get the ChaCha20+Poly1305 "ctmulq" implementation, if available.
+ *
+ * This function returns a pointer to the `br_poly1305_ctmulq_run()`
+ * function if supported on the current platform; otherwise, it returns 0.
+ *
+ * \return the ctmulq ChaCha20+Poly1305 implementation, or 0.
+ */
+br_poly1305_run br_poly1305_ctmulq_get(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/inc/bearssl_ec.h b/inc/bearssl_ec.h
new file mode 100644
index 000000000000..f954309eb6c1
--- /dev/null
+++ b/inc/bearssl_ec.h
@@ -0,0 +1,967 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef BR_BEARSSL_EC_H__
+#define BR_BEARSSL_EC_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "bearssl_rand.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file bearssl_ec.h
+ *
+ * # Elliptic Curves
+ *
+ * This file documents the EC implementations provided with BearSSL, and
+ * ECDSA.
+ *
+ * ## Elliptic Curve API
+ *
+ * Only "named curves" are supported. Each EC implementation supports
+ * one or several named curves, identified by symbolic identifiers.
+ * These identifiers are small integers, that correspond to the values
+ * registered by the
+ * [IANA](http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8).
+ *
+ * Since all currently defined elliptic curve identifiers are in the 0..31
+ * range, it is convenient to encode support of some curves in a 32-bit
+ * word, such that bit x corresponds to curve of identifier x.
+ *
+ * An EC implementation is incarnated by a `br_ec_impl` instance, that
+ * offers the following fields:
+ *
+ * - `supported_curves`
+ *
+ * A 32-bit word that documents the identifiers of the curves supported
+ * by this implementation.
+ *
+ * - `generator()`
+ *
+ * Callback method that returns a pointer to the conventional generator
+ * point for that curve.
+ *
+ * - `order()`
+ *
+ * Callback method that returns a pointer to the subgroup order for
+ * that curve. That value uses unsigned big-endian encoding.
+ *
+ * - `xoff()`
+ *
+ * Callback method that returns the offset and length of the X
+ * coordinate in an encoded point.
+ *
+ * - `mul()`
+ *
+ * Multiply a curve point with an integer.
+ *
+ * - `mulgen()`
+ *
+ * Multiply the curve generator with an integer. This may be faster
+ * than the generic `mul()`.
+ *
+ * - `muladd()`
+ *
+ * Multiply two curve points by two integers, and return the sum of
+ * the two products.
+ *
+ * All curve points are represented in uncompressed format. The `mul()`
+ * and `muladd()` methods take care to validate that the provided points
+ * are really part of the relevant curve subgroup.
+ *
+ * For all point multiplication functions, the following holds:
+ *
+ * - Functions validate that the provided points are valid members
+ * of the relevant curve subgroup. An error is reported if that is
+ * not the case.
+ *
+ * - Processing is constant-time, even if the point operands are not
+ * valid. This holds for both the source and resulting points, and
+ * the multipliers (integers). Only the byte length of the provided
+ * multiplier arrays (not their actual value length in bits) may
+ * leak through timing-based side channels.
+ *
+ * - The multipliers (integers) MUST be lower than the subgroup order.
+ * If this property is not met, then the result is indeterminate,
+ * but an error value is not ncessearily returned.
+ *
+ *
+ * ## ECDSA
+ *
+ * ECDSA signatures have two standard formats, called "raw" and "asn1".
+ * Internally, such a signature is a pair of modular integers `(r,s)`.
+ * The "raw" format is the concatenation of the unsigned big-endian
+ * encodings of these two integers, possibly left-padded with zeros so
+ * that they have the same encoded length. The "asn1" format is the
+ * DER encoding of an ASN.1 structure that contains the two integer
+ * values:
+ *
+ * ECDSASignature ::= SEQUENCE {
+ * r INTEGER,
+ * s INTEGER
+ * }
+ *
+ * In general, in all of X.509 and SSL/TLS, the "asn1" format is used.
+ * BearSSL offers ECDSA implementations for both formats; conversion
+ * functions between the two formats are also provided. Conversion of a
+ * "raw" format signature into "asn1" may enlarge a signature by no more
+ * than 9 bytes for all supported curves; conversely, conversion of an
+ * "asn1" signature to "raw" may expand the signature but the "raw"
+ * length will never be more than twice the length of the "asn1" length
+ * (and usually it will be shorter).
+ *
+ * Note that for a given signature, the "raw" format is not fully
+ * deterministic, in that it does not enforce a minimal common length.
+ */
+
+/*
+ * Standard curve ID. These ID are equal to the assigned numerical
+ * identifiers assigned to these curves for TLS:
+ * http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
+ */
+
+/** \brief Identifier for named curve sect163k1. */
+#define BR_EC_sect163k1 1
+
+/** \brief Identifier for named curve sect163r1. */
+#define BR_EC_sect163r1 2
+
+/** \brief Identifier for named curve sect163r2. */
+#define BR_EC_sect163r2 3
+
+/** \brief Identifier for named curve sect193r1. */
+#define BR_EC_sect193r1 4
+
+/** \brief Identifier for named curve sect193r2. */
+#define BR_EC_sect193r2 5
+
+/** \brief Identifier for named curve sect233k1. */
+#define BR_EC_sect233k1 6
+
+/** \brief Identifier for named curve sect233r1. */
+#define BR_EC_sect233r1 7
+
+/** \brief Identifier for named curve sect239k1. */
+#define BR_EC_sect239k1 8
+
+/** \brief Identifier for named curve sect283k1. */
+#define BR_EC_sect283k1 9
+
+/** \brief Identifier for named curve sect283r1. */
+#define BR_EC_sect283r1 10
+
+/** \brief Identifier for named curve sect409k1. */
+#define BR_EC_sect409k1 11
+
+/** \brief Identifier for named curve sect409r1. */
+#define BR_EC_sect409r1 12
+
+/** \brief Identifier for named curve sect571k1. */
+#define BR_EC_sect571k1 13
+
+/** \brief Identifier for named curve sect571r1. */
+#define BR_EC_sect571r1 14
+
+/** \brief Identifier for named curve secp160k1. */
+#define BR_EC_secp160k1 15
+
+/** \brief Identifier for named curve secp160r1. */
+#define BR_EC_secp160r1 16
+
+/** \brief Identifier for named curve secp160r2. */
+#define BR_EC_secp160r2 17
+
+/** \brief Identifier for named curve secp192k1. */
+#define BR_EC_secp192k1 18
+
+/** \brief Identifier for named curve secp192r1. */
+#define BR_EC_secp192r1 19
+
+/** \brief Identifier for named curve secp224k1. */
+#define BR_EC_secp224k1 20
+
+/** \brief Identifier for named curve secp224r1. */
+#define BR_EC_secp224r1 21
+
+/** \brief Identifier for named curve secp256k1. */
+#define BR_EC_secp256k1 22
+
+/** \brief Identifier for named curve secp256r1. */
+#define BR_EC_secp256r1 23
+
+/** \brief Identifier for named curve secp384r1. */
+#define BR_EC_secp384r1 24
+
+/** \brief Identifier for named curve secp521r1. */
+#define BR_EC_secp521r1 25
+
+/** \brief Identifier for named curve brainpoolP256r1. */
+#define BR_EC_brainpoolP256r1 26
+
+/** \brief Identifier for named curve brainpoolP384r1. */
+#define BR_EC_brainpoolP384r1 27
+
+/** \brief Identifier for named curve brainpoolP512r1. */
+#define BR_EC_brainpoolP512r1 28
+
+/** \brief Identifier for named curve Curve25519. */
+#define BR_EC_curve25519 29
+
+/** \brief Identifier for named curve Curve448. */
+#define BR_EC_curve448 30
+
+/**
+ * \brief Structure for an EC public key.
+ */
+typedef struct {
+ /** \brief Identifier for the curve used by this key. */
+ int curve;
+ /** \brief Public curve point (uncompressed format). */
+ unsigned char *q;
+ /** \brief Length of public curve point (in bytes). */
+ size_t qlen;
+} br_ec_public_key;
+
+/**
+ * \brief Structure for an EC private key.
+ *
+ * The private key is an integer modulo the curve subgroup order. The
+ * encoding below tolerates extra leading zeros. In general, it is
+ * recommended that the private key has the same length as the curve
+ * subgroup order.
+ */
+typedef struct {
+ /** \brief Identifier for the curve used by this key. */
+ int curve;
+ /** \brief Private key (integer, unsigned big-endian encoding). */
+ unsigned char *x;
+ /** \brief Private key length (in bytes). */
+ size_t xlen;
+} br_ec_private_key;
+
+/**
+ * \brief Type for an EC implementation.
+ */
+typedef struct {
+ /**
+ * \brief Supported curves.
+ *
+ * This word is a bitfield: bit `x` is set if the curve of ID `x`
+ * is supported. E.g. an implementation supporting both NIST P-256
+ * (secp256r1, ID 23) and NIST P-384 (secp384r1, ID 24) will have
+ * value `0x01800000` in this field.
+ */
+ uint32_t supported_curves;
+
+ /**
+ * \brief Get the conventional generator.
+ *
+ * This function returns the conventional generator (encoded
+ * curve point) for the specified curve. This function MUST NOT
+ * be called if the curve is not supported.
+ *
+ * \param curve curve identifier.
+ * \param len receiver for the encoded generator length (in bytes).
+ * \return the encoded generator.
+ */
+ const unsigned char *(*generator)(int curve, size_t *len);
+
+ /**
+ * \brief Get the subgroup order.
+ *
+ * This function returns the order of the subgroup generated by
+ * the conventional generator, for the specified curve. Unsigned
+ * big-endian encoding is used. This function MUST NOT be called
+ * if the curve is not supported.
+ *
+ * \param curve curve identifier.
+ * \param len receiver for the encoded order length (in bytes).
+ * \return the encoded order.
+ */
+ const unsigned char *(*order)(int curve, size_t *len);
+
+ /**
+ * \brief Get the offset and length for the X coordinate.
+ *
+ * This function returns the offset and length (in bytes) of
+ * the X coordinate in an encoded non-zero point.
+ *
+ * \param curve curve identifier.
+ * \param len receiver for the X coordinate length (in bytes).
+ * \return the offset for the X coordinate (in bytes).
+ */
+ size_t (*xoff)(int curve, size_t *len);
+
+ /**
+ * \brief Multiply a curve point by an integer.
+ *
+ * The source point is provided in array `G` (of size `Glen` bytes);
+ * the multiplication result is written over it. The multiplier
+ * `x` (of size `xlen` bytes) uses unsigned big-endian encoding.
+ *
+ * Rules:
+ *
+ * - The specified curve MUST be supported.
+ *
+ * - The source point must be a valid point on the relevant curve
+ * subgroup (and not the "point at infinity" either). If this is
+ * not the case, then this function returns an error (0).
+ *
+ * - The multiplier integer MUST be non-zero and less than the
+ * curve subgroup order. If this property does not hold, then
+ * the result is indeterminate and an error code is not
+ * guaranteed.
+ *
+ * Returned value is 1 on success, 0 on error. On error, the
+ * contents of `G` are indeterminate.
+ *
+ * \param G point to multiply.
+ * \param Glen length of the encoded point (in bytes).
+ * \param x multiplier (unsigned big-endian).
+ * \param xlen multiplier length (in bytes).
+ * \param curve curve identifier.
+ * \return 1 on success, 0 on error.
+ */
+ uint32_t (*mul)(unsigned char *G, size_t Glen,
+ const unsigned char *x, size_t xlen, int curve);
+
+ /**
+ * \brief Multiply the generator by an integer.
+ *
+ * The multiplier MUST be non-zero and less than the curve
+ * subgroup order. Results are indeterminate if this property
+ * does not hold.
+ *
+ * \param R output buffer for the point.
+ * \param x multiplier (unsigned big-endian).
+ * \param xlen multiplier length (in bytes).
+ * \param curve curve identifier.
+ * \return encoded result point length (in bytes).
+ */
+ size_t (*mulgen)(unsigned char *R,
+ const unsigned char *x, size_t xlen, int curve);
+
+ /**
+ * \brief Multiply two points by two integers and add the
+ * results.
+ *
+ * The point `x*A + y*B` is computed and written back in the `A`
+ * array.
+ *
+ * Rules:
+ *
+ * - The specified curve MUST be supported.
+ *
+ * - The source points (`A` and `B`) must be valid points on
+ * the relevant curve subgroup (and not the "point at
+ * infinity" either). If this is not the case, then this
+ * function returns an error (0).
+ *
+ * - If the `B` pointer is `NULL`, then the conventional
+ * subgroup generator is used. With some implementations,
+ * this may be faster than providing a pointer to the
+ * generator.
+ *
+ * - The multiplier integers (`x` and `y`) MUST be non-zero
+ * and less than the curve subgroup order. If either integer
+ * is zero, then an error is reported, but if one of them is
+ * not lower than the subgroup order, then the result is
+ * indeterminate and an error code is not guaranteed.
+ *
+ * - If the final result is the point at infinity, then an
+ * error is returned.
+ *
+ * Returned value is 1 on success, 0 on error. On error, the
+ * contents of `A` are indeterminate.
+ *
+ * \param A first point to multiply.
+ * \param B second point to multiply (`NULL` for the generator).
+ * \param len common length of the encoded points (in bytes).
+ * \param x multiplier for `A` (unsigned big-endian).
+ * \param xlen length of multiplier for `A` (in bytes).
+ * \param y multiplier for `A` (unsigned big-endian).
+ * \param ylen length of multiplier for `A` (in bytes).
+ * \param curve curve identifier.
+ * \return 1 on success, 0 on error.
+ */
+ uint32_t (*muladd)(unsigned char *A, const unsigned char *B, size_t len,
+ const unsigned char *x, size_t xlen,
+ const unsigned char *y, size_t ylen, int curve);
+} br_ec_impl;
+
+/**
+ * \brief EC implementation "i31".
+ *
+ * This implementation internally uses generic code for modular integers,
+ * with a representation as sequences of 31-bit words. It supports secp256r1,
+ * secp384r1 and secp521r1 (aka NIST curves P-256, P-384 and P-521).
+ */
+extern const br_ec_impl br_ec_prime_i31;
+
+/**
+ * \brief EC implementation "i15".
+ *
+ * This implementation internally uses generic code for modular integers,
+ * with a representation as sequences of 15-bit words. It supports secp256r1,
+ * secp384r1 and secp521r1 (aka NIST curves P-256, P-384 and P-521).
+ */
+extern const br_ec_impl br_ec_prime_i15;
+
+/**
+ * \brief EC implementation "m15" for P-256.
+ *
+ * This implementation uses specialised code for curve secp256r1 (also
+ * known as NIST P-256), with optional Karatsuba decomposition, and fast
+ * modular reduction thanks to the field modulus special format. Only
+ * 32-bit multiplications are used (with 32-bit results, not 64-bit).
+ */
+extern const br_ec_impl br_ec_p256_m15;
+
+/**
+ * \brief EC implementation "m31" for P-256.
+ *
+ * This implementation uses specialised code for curve secp256r1 (also
+ * known as NIST P-256), relying on multiplications of 31-bit values
+ * (MUL31).
+ */
+extern const br_ec_impl br_ec_p256_m31;
+
+/**
+ * \brief EC implementation "m62" (specialised code) for P-256.
+ *
+ * This implementation uses custom code relying on multiplication of
+ * integers up to 64 bits, with a 128-bit result. This implementation is
+ * defined only on platforms that offer the 64x64->128 multiplication
+ * support; use `br_ec_p256_m62_get()` to dynamically obtain a pointer
+ * to that implementation.
+ */
+extern const br_ec_impl br_ec_p256_m62;
+
+/**
+ * \brief Get the "m62" implementation of P-256, if available.
+ *
+ * \return the implementation, or 0.
+ */
+const br_ec_impl *br_ec_p256_m62_get(void);
+
+/**
+ * \brief EC implementation "m64" (specialised code) for P-256.
+ *
+ * This implementation uses custom code relying on multiplication of
+ * integers up to 64 bits, with a 128-bit result. This implementation is
+ * defined only on platforms that offer the 64x64->128 multiplication
+ * support; use `br_ec_p256_m64_get()` to dynamically obtain a pointer
+ * to that implementation.
+ */
+extern const br_ec_impl br_ec_p256_m64;
+
+/**
+ * \brief Get the "m64" implementation of P-256, if available.
+ *
+ * \return the implementation, or 0.
+ */
+const br_ec_impl *br_ec_p256_m64_get(void);
+
+/**
+ * \brief EC implementation "i15" (generic code) for Curve25519.
+ *
+ * This implementation uses the generic code for modular integers (with
+ * 15-bit words) to support Curve25519. Due to the specificities of the
+ * curve definition, the following applies:
+ *
+ * - `muladd()` is not implemented (the function returns 0 systematically).
+ * - `order()` returns 2^255-1, since the point multiplication algorithm
+ * accepts any 32-bit integer as input (it clears the top bit and low
+ * three bits systematically).
+ */
+extern const br_ec_impl br_ec_c25519_i15;
+
+/**
+ * \brief EC implementation "i31" (generic code) for Curve25519.
+ *
+ * This implementation uses the generic code for modular integers (with
+ * 31-bit words) to support Curve25519. Due to the specificities of the
+ * curve definition, the following applies:
+ *
+ * - `muladd()` is not implemented (the function returns 0 systematically).
+ * - `order()` returns 2^255-1, since the point multiplication algorithm
+ * accepts any 32-bit integer as input (it clears the top bit and low
+ * three bits systematically).
+ */
+extern const br_ec_impl br_ec_c25519_i31;
+
+/**
+ * \brief EC implementation "m15" (specialised code) for Curve25519.
+ *
+ * This implementation uses custom code relying on multiplication of
+ * integers up to 15 bits. Due to the specificities of the curve
+ * definition, the following applies:
+ *
+ * - `muladd()` is not implemented (the function returns 0 systematically).
+ * - `order()` returns 2^255-1, since the point multiplication algorithm
+ * accepts any 32-bit integer as input (it clears the top bit and low
+ * three bits systematically).
+ */
+extern const br_ec_impl br_ec_c25519_m15;
+
+/**
+ * \brief EC implementation "m31" (specialised code) for Curve25519.
+ *
+ * This implementation uses custom code relying on multiplication of
+ * integers up to 31 bits. Due to the specificities of the curve
+ * definition, the following applies:
+ *
+ * - `muladd()` is not implemented (the function returns 0 systematically).
+ * - `order()` returns 2^255-1, since the point multiplication algorithm
+ * accepts any 32-bit integer as input (it clears the top bit and low
+ * three bits systematically).
+ */
+extern const br_ec_impl br_ec_c25519_m31;
+
+/**
+ * \brief EC implementation "m62" (specialised code) for Curve25519.
+ *
+ * This implementation uses custom code relying on multiplication of
+ * integers up to 62 bits, with a 124-bit result. This implementation is
+ * defined only on platforms that offer the 64x64->128 multiplication
+ * support; use `br_ec_c25519_m62_get()` to dynamically obtain a pointer
+ * to that implementation. Due to the specificities of the curve
+ * definition, the following applies:
+ *
+ * - `muladd()` is not implemented (the function returns 0 systematically).
+ * - `order()` returns 2^255-1, since the point multiplication algorithm
+ * accepts any 32-bit integer as input (it clears the top bit and low
+ * three bits systematically).
+ */
+extern const br_ec_impl br_ec_c25519_m62;
+
+/**
+ * \brief Get the "m62" implementation of Curve25519, if available.
+ *
+ * \return the implementation, or 0.
+ */
+const br_ec_impl *br_ec_c25519_m62_get(void);
+
+/**
+ * \brief EC implementation "m64" (specialised code) for Curve25519.
+ *
+ * This implementation uses custom code relying on multiplication of
+ * integers up to 64 bits, with a 128-bit result. This implementation is
+ * defined only on platforms that offer the 64x64->128 multiplication
+ * support; use `br_ec_c25519_m64_get()` to dynamically obtain a pointer
+ * to that implementation. Due to the specificities of the curve
+ * definition, the following applies:
+ *
+ * - `muladd()` is not implemented (the function returns 0 systematically).
+ * - `order()` returns 2^255-1, since the point multiplication algorithm
+ * accepts any 32-bit integer as input (it clears the top bit and low
+ * three bits systematically).
+ */
+extern const br_ec_impl br_ec_c25519_m64;
+
+/**
+ * \brief Get the "m64" implementation of Curve25519, if available.
+ *
+ * \return the implementation, or 0.
+ */
+const br_ec_impl *br_ec_c25519_m64_get(void);
+
+/**
+ * \brief Aggregate EC implementation "m15".
+ *
+ * This implementation is a wrapper for:
+ *
+ * - `br_ec_c25519_m15` for Curve25519
+ * - `br_ec_p256_m15` for NIST P-256
+ * - `br_ec_prime_i15` for other curves (NIST P-384 and NIST-P512)
+ */
+extern const br_ec_impl br_ec_all_m15;
+
+/**
+ * \brief Aggregate EC implementation "m31".
+ *
+ * This implementation is a wrapper for:
+ *
+ * - `br_ec_c25519_m31` for Curve25519
+ * - `br_ec_p256_m31` for NIST P-256
+ * - `br_ec_prime_i31` for other curves (NIST P-384 and NIST-P512)
+ */
+extern const br_ec_impl br_ec_all_m31;
+
+/**
+ * \brief Get the "default" EC implementation for the current system.
+ *
+ * This returns a pointer to the preferred implementation on the
+ * current system.
+ *
+ * \return the default EC implementation.
+ */
+const br_ec_impl *br_ec_get_default(void);
+
+/**
+ * \brief Convert a signature from "raw" to "asn1".
+ *
+ * Conversion is done "in place" and the new length is returned.
+ * Conversion may enlarge the signature, but by no more than 9 bytes at
+ * most. On error, 0 is returned (error conditions include an odd raw
+ * signature length, or an oversized integer).
+ *
+ * \param sig signature to convert.
+ * \param sig_len signature length (in bytes).
+ * \return the new signature length, or 0 on error.
+ */
+size_t br_ecdsa_raw_to_asn1(void *sig, size_t sig_len);
+
+/**
+ * \brief Convert a signature from "asn1" to "raw".
+ *
+ * Conversion is done "in place" and the new length is returned.
+ * Conversion may enlarge the signature, but the new signature length
+ * will be less than twice the source length at most. On error, 0 is
+ * returned (error conditions include an invalid ASN.1 structure or an
+ * oversized integer).
+ *
+ * \param sig signature to convert.
+ * \param sig_len signature length (in bytes).
+ * \return the new signature length, or 0 on error.
+ */
+size_t br_ecdsa_asn1_to_raw(void *sig, size_t sig_len);
+
+/**
+ * \brief Type for an ECDSA signer function.
+ *
+ * A pointer to the EC implementation is provided. The hash value is
+ * assumed to have the length inferred from the designated hash function
+ * class.
+ *
+ * Signature is written in the buffer pointed to by `sig`, and the length
+ * (in bytes) is returned. On error, nothing is written in the buffer,
+ * and 0 is returned. This function returns 0 if the specified curve is
+ * not supported by the provided EC implementation.
+ *
+ * The signature format is either "raw" or "asn1", depending on the
+ * implementation; maximum length is predictable from the implemented
+ * curve:
+ *
+ * | curve | raw | asn1 |
+ * | :--------- | --: | ---: |
+ * | NIST P-256 | 64 | 72 |
+ * | NIST P-384 | 96 | 104 |
+ * | NIST P-521 | 132 | 139 |
+ *
+ * \param impl EC implementation to use.
+ * \param hf hash function used to process the data.
+ * \param hash_value signed data (hashed).
+ * \param sk EC private key.
+ * \param sig destination buffer.
+ * \return the signature length (in bytes), or 0 on error.
+ */
+typedef size_t (*br_ecdsa_sign)(const br_ec_impl *impl,
+ const br_hash_class *hf, const void *hash_value,
+ const br_ec_private_key *sk, void *sig);
+
+/**
+ * \brief Type for an ECDSA signature verification function.
+ *
+ * A pointer to the EC implementation is provided. The hashed value,
+ * computed over the purportedly signed data, is also provided with
+ * its length.
+ *
+ * The signature format is either "raw" or "asn1", depending on the
+ * implementation.
+ *
+ * Returned value is 1 on success (valid signature), 0 on error. This
+ * function returns 0 if the specified curve is not supported by the
+ * provided EC implementation.
+ *
+ * \param impl EC implementation to use.
+ * \param hash signed data (hashed).
+ * \param hash_len hash value length (in bytes).
+ * \param pk EC public key.
+ * \param sig signature.
+ * \param sig_len signature length (in bytes).
+ * \return 1 on success, 0 on error.
+ */
+typedef uint32_t (*br_ecdsa_vrfy)(const br_ec_impl *impl,
+ const void *hash, size_t hash_len,
+ const br_ec_public_key *pk, const void *sig, size_t sig_len);
+
+/**
+ * \brief ECDSA signature generator, "i31" implementation, "asn1" format.
+ *
+ * \see br_ecdsa_sign()
+ *
+ * \param impl EC implementation to use.
+ * \param hf hash function used to process the data.
+ * \param hash_value signed data (hashed).
+ * \param sk EC private key.
+ * \param sig destination buffer.
+ * \return the signature length (in bytes), or 0 on error.
+ */
+size_t br_ecdsa_i31_sign_asn1(const br_ec_impl *impl,
+ const br_hash_class *hf, const void *hash_value,
+ const br_ec_private_key *sk, void *sig);
+
+/**
+ * \brief ECDSA signature generator, "i31" implementation, "raw" format.
+ *
+ * \see br_ecdsa_sign()
+ *
+ * \param impl EC implementation to use.
+ * \param hf hash function used to process the data.
+ * \param hash_value signed data (hashed).
+ * \param sk EC private key.
+ * \param sig destination buffer.
+ * \return the signature length (in bytes), or 0 on error.
+ */
+size_t br_ecdsa_i31_sign_raw(const br_ec_impl *impl,
+ const br_hash_class *hf, const void *hash_value,
+ const br_ec_private_key *sk, void *sig);
+
+/**
+ * \brief ECDSA signature verifier, "i31" implementation, "asn1" format.
+ *
+ * \see br_ecdsa_vrfy()
+ *
+ * \param impl EC implementation to use.
+ * \param hash signed data (hashed).
+ * \param hash_len hash value length (in bytes).
+ * \param pk EC public key.
+ * \param sig signature.
+ * \param sig_len signature length (in bytes).
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_ecdsa_i31_vrfy_asn1(const br_ec_impl *impl,
+ const void *hash, size_t hash_len,
+ const br_ec_public_key *pk, const void *sig, size_t sig_len);
+
+/**
+ * \brief ECDSA signature verifier, "i31" implementation, "raw" format.
+ *
+ * \see br_ecdsa_vrfy()
+ *
+ * \param impl EC implementation to use.
+ * \param hash signed data (hashed).
+ * \param hash_len hash value length (in bytes).
+ * \param pk EC public key.
+ * \param sig signature.
+ * \param sig_len signature length (in bytes).
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_ecdsa_i31_vrfy_raw(const br_ec_impl *impl,
+ const void *hash, size_t hash_len,
+ const br_ec_public_key *pk, const void *sig, size_t sig_len);
+
+/**
+ * \brief ECDSA signature generator, "i15" implementation, "asn1" format.
+ *
+ * \see br_ecdsa_sign()
+ *
+ * \param impl EC implementation to use.
+ * \param hf hash function used to process the data.
+ * \param hash_value signed data (hashed).
+ * \param sk EC private key.
+ * \param sig destination buffer.
+ * \return the signature length (in bytes), or 0 on error.
+ */
+size_t br_ecdsa_i15_sign_asn1(const br_ec_impl *impl,
+ const br_hash_class *hf, const void *hash_value,
+ const br_ec_private_key *sk, void *sig);
+
+/**
+ * \brief ECDSA signature generator, "i15" implementation, "raw" format.
+ *
+ * \see br_ecdsa_sign()
+ *
+ * \param impl EC implementation to use.
+ * \param hf hash function used to process the data.
+ * \param hash_value signed data (hashed).
+ * \param sk EC private key.
+ * \param sig destination buffer.
+ * \return the signature length (in bytes), or 0 on error.
+ */
+size_t br_ecdsa_i15_sign_raw(const br_ec_impl *impl,
+ const br_hash_class *hf, const void *hash_value,
+ const br_ec_private_key *sk, void *sig);
+
+/**
+ * \brief ECDSA signature verifier, "i15" implementation, "asn1" format.
+ *
+ * \see br_ecdsa_vrfy()
+ *
+ * \param impl EC implementation to use.
+ * \param hash signed data (hashed).
+ * \param hash_len hash value length (in bytes).
+ * \param pk EC public key.
+ * \param sig signature.
+ * \param sig_len signature length (in bytes).
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_ecdsa_i15_vrfy_asn1(const br_ec_impl *impl,
+ const void *hash, size_t hash_len,
+ const br_ec_public_key *pk, const void *sig, size_t sig_len);
+
+/**
+ * \brief ECDSA signature verifier, "i15" implementation, "raw" format.
+ *
+ * \see br_ecdsa_vrfy()
+ *
+ * \param impl EC implementation to use.
+ * \param hash signed data (hashed).
+ * \param hash_len hash value length (in bytes).
+ * \param pk EC public key.
+ * \param sig signature.
+ * \param sig_len signature length (in bytes).
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_ecdsa_i15_vrfy_raw(const br_ec_impl *impl,
+ const void *hash, size_t hash_len,
+ const br_ec_public_key *pk, const void *sig, size_t sig_len);
+
+/**
+ * \brief Get "default" ECDSA implementation (signer, asn1 format).
+ *
+ * This returns the preferred implementation of ECDSA signature generation
+ * ("asn1" output format) on the current system.
+ *
+ * \return the default implementation.
+ */
+br_ecdsa_sign br_ecdsa_sign_asn1_get_default(void);
+
+/**
+ * \brief Get "default" ECDSA implementation (signer, raw format).
+ *
+ * This returns the preferred implementation of ECDSA signature generation
+ * ("raw" output format) on the current system.
+ *
+ * \return the default implementation.
+ */
+br_ecdsa_sign br_ecdsa_sign_raw_get_default(void);
+
+/**
+ * \brief Get "default" ECDSA implementation (verifier, asn1 format).
+ *
+ * This returns the preferred implementation of ECDSA signature verification
+ * ("asn1" output format) on the current system.
+ *
+ * \return the default implementation.
+ */
+br_ecdsa_vrfy br_ecdsa_vrfy_asn1_get_default(void);
+
+/**
+ * \brief Get "default" ECDSA implementation (verifier, raw format).
+ *
+ * This returns the preferred implementation of ECDSA signature verification
+ * ("raw" output format) on the current system.
+ *
+ * \return the default implementation.
+ */
+br_ecdsa_vrfy br_ecdsa_vrfy_raw_get_default(void);
+
+/**
+ * \brief Maximum size for EC private key element buffer.
+ *
+ * This is the largest number of bytes that `br_ec_keygen()` may need or
+ * ever return.
+ */
+#define BR_EC_KBUF_PRIV_MAX_SIZE 72
+
+/**
+ * \brief Maximum size for EC public key element buffer.
+ *
+ * This is the largest number of bytes that `br_ec_compute_public()` may
+ * need or ever return.
+ */
+#define BR_EC_KBUF_PUB_MAX_SIZE 145
+
+/**
+ * \brief Generate a new EC private key.
+ *
+ * If the specified `curve` is not supported by the elliptic curve
+ * implementation (`impl`), then this function returns zero.
+ *
+ * The `sk` structure fields are set to the new private key data. In
+ * particular, `sk.x` is made to point to the provided key buffer (`kbuf`),
+ * in which the actual private key data is written. That buffer is assumed
+ * to be large enough. The `BR_EC_KBUF_PRIV_MAX_SIZE` defines the maximum
+ * size for all supported curves.
+ *
+ * The number of bytes used in `kbuf` is returned. If `kbuf` is `NULL`, then
+ * the private key is not actually generated, and `sk` may also be `NULL`;
+ * the minimum length for `kbuf` is still computed and returned.
+ *
+ * If `sk` is `NULL` but `kbuf` is not `NULL`, then the private key is
+ * still generated and stored in `kbuf`.
+ *
+ * \param rng_ctx source PRNG context (already initialized).
+ * \param impl the elliptic curve implementation.
+ * \param sk the private key structure to fill, or `NULL`.
+ * \param kbuf the key element buffer, or `NULL`.
+ * \param curve the curve identifier.
+ * \return the key data length (in bytes), or zero.
+ */
+size_t br_ec_keygen(const br_prng_class **rng_ctx,
+ const br_ec_impl *impl, br_ec_private_key *sk,
+ void *kbuf, int curve);
+
+/**
+ * \brief Compute EC public key from EC private key.
+ *
+ * This function uses the provided elliptic curve implementation (`impl`)
+ * to compute the public key corresponding to the private key held in `sk`.
+ * The public key point is written into `kbuf`, which is then linked from
+ * the `*pk` structure. The size of the public key point, i.e. the number
+ * of bytes used in `kbuf`, is returned.
+ *
+ * If `kbuf` is `NULL`, then the public key point is NOT computed, and
+ * the public key structure `*pk` is unmodified (`pk` may be `NULL` in
+ * that case). The size of the public key point is still returned.
+ *
+ * If `pk` is `NULL` but `kbuf` is not `NULL`, then the public key
+ * point is computed and stored in `kbuf`, and its size is returned.
+ *
+ * If the curve used by the private key is not supported by the curve
+ * implementation, then this function returns zero.
+ *
+ * The private key MUST be valid. An off-range private key value is not
+ * necessarily detected, and leads to unpredictable results.
+ *
+ * \param impl the elliptic curve implementation.
+ * \param pk the public key structure to fill (or `NULL`).
+ * \param kbuf the public key point buffer (or `NULL`).
+ * \param sk the source private key.
+ * \return the public key point length (in bytes), or zero.
+ */
+size_t br_ec_compute_pub(const br_ec_impl *impl, br_ec_public_key *pk,
+ void *kbuf, const br_ec_private_key *sk);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/inc/bearssl_hash.h b/inc/bearssl_hash.h
new file mode 100644
index 000000000000..3b15ba7ca487
--- /dev/null
+++ b/inc/bearssl_hash.h
@@ -0,0 +1,1346 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef BR_BEARSSL_HASH_H__
+#define BR_BEARSSL_HASH_H__
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file bearssl_hash.h
+ *
+ * # Hash Functions
+ *
+ * This file documents the API for hash functions.
+ *
+ *
+ * ## Procedural API
+ *
+ * For each implemented hash function, of name "`xxx`", the following
+ * elements are defined:
+ *
+ * - `br_xxx_vtable`
+ *
+ * An externally defined instance of `br_hash_class`.
+ *
+ * - `br_xxx_SIZE`
+ *
+ * A macro that evaluates to the output size (in bytes) of the
+ * hash function.
+ *
+ * - `br_xxx_ID`
+ *
+ * A macro that evaluates to a symbolic identifier for the hash
+ * function. Such identifiers are used with HMAC and signature
+ * algorithm implementations.
+ *
+ * NOTE: for the "standard" hash functions defined in [the TLS
+ * standard](https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1),
+ * the symbolic identifiers match the constants used in TLS, i.e.
+ * 1 to 6 for MD5, SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512,
+ * respectively.
+ *
+ * - `br_xxx_context`
+ *
+ * Context for an ongoing computation. It is allocated by the
+ * caller, and a pointer to it is passed to all functions. A
+ * context contains no interior pointer, so it can be moved around
+ * and cloned (with a simple `memcpy()` or equivalent) in order to
+ * capture the function state at some point. Computations that use
+ * distinct context structures are independent of each other. The
+ * first field of `br_xxx_context` is always a pointer to the
+ * `br_xxx_vtable` structure; `br_xxx_init()` sets that pointer.
+ *
+ * - `br_xxx_init(br_xxx_context *ctx)`
+ *
+ * Initialise the provided context. Previous contents of the structure
+ * are ignored. This calls resets the context to the start of a new
+ * hash computation; it also sets the first field of the context
+ * structure (called `vtable`) to a pointer to the statically
+ * allocated constant `br_xxx_vtable` structure.
+ *
+ * - `br_xxx_update(br_xxx_context *ctx, const void *data, size_t len)`
+ *
+ * Add some more bytes to the hash computation represented by the
+ * provided context.
+ *
+ * - `br_xxx_out(const br_xxx_context *ctx, void *out)`
+ *
+ * Complete the hash computation and write the result in the provided
+ * buffer. The output buffer MUST be large enough to accommodate the
+ * result. The context is NOT modified by this operation, so this
+ * function can be used to get a "partial hash" while still keeping
+ * the possibility of adding more bytes to the input.
+ *
+ * - `br_xxx_state(const br_xxx_context *ctx, void *out)`
+ *
+ * Get a copy of the "current state" for the computation so far. For
+ * MD functions (MD5, SHA-1, SHA-2 family), this is the running state
+ * resulting from the processing of the last complete input block.
+ * Returned value is the current input length (in bytes).
+ *
+ * - `br_xxx_set_state(br_xxx_context *ctx, const void *stb, uint64_t count)`
+ *
+ * Set the internal state to the provided values. The 'stb' and
+ * 'count' values shall match that which was obtained from
+ * `br_xxx_state()`. This restores the hash state only if the state
+ * values were at an appropriate block boundary. This does NOT set
+ * the `vtable` pointer in the context.
+ *
+ * Context structures can be discarded without any explicit deallocation.
+ * Hash function implementations are purely software and don't reserve
+ * any resources outside of the context structure itself.
+ *
+ *
+ * ## Object-Oriented API
+ *
+ * For each hash function that follows the procedural API described
+ * above, an object-oriented API is also provided. In that API, function
+ * pointers from the vtable (`br_xxx_vtable`) are used. The vtable
+ * incarnates object-oriented programming. An introduction on the OOP
+ * concept used here can be read on the BearSSL Web site:<br />
+ * &nbsp;&nbsp;&nbsp;[https://www.bearssl.org/oop.html](https://www.bearssl.org/oop.html)
+ *
+ * The vtable offers functions called `init()`, `update()`, `out()`,
+ * `set()` and `set_state()`, which are in fact the functions from
+ * the procedural API. That vtable also contains two informative fields:
+ *
+ * - `context_size`
+ *
+ * The size of the context structure (`br_xxx_context`), in bytes.
+ * This can be used by generic implementations to perform dynamic
+ * context allocation.
+ *
+ * - `desc`
+ *
+ * A "descriptor" field that encodes some information on the hash
+ * function: symbolic identifier, output size, state size,
+ * internal block size, details on the padding.
+ *
+ * Users of this object-oriented API (in particular generic HMAC
+ * implementations) may make the following assumptions:
+ *
+ * - Hash output size is no more than 64 bytes.
+ * - Hash internal state size is no more than 64 bytes.
+ * - Internal block size is a power of two, no less than 16 and no more
+ * than 256.
+ *
+ *
+ * ## Implemented Hash Functions
+ *
+ * Implemented hash functions are:
+ *
+ * | Function | Name | Output length | State length |
+ * | :-------- | :------ | :-----------: | :----------: |
+ * | MD5 | md5 | 16 | 16 |
+ * | SHA-1 | sha1 | 20 | 20 |
+ * | SHA-224 | sha224 | 28 | 32 |
+ * | SHA-256 | sha256 | 32 | 32 |
+ * | SHA-384 | sha384 | 48 | 64 |
+ * | SHA-512 | sha512 | 64 | 64 |
+ * | MD5+SHA-1 | md5sha1 | 36 | 36 |
+ *
+ * (MD5+SHA-1 is the concatenation of MD5 and SHA-1 computed over the
+ * same input; in the implementation, the internal data buffer is
+ * shared, thus making it more memory-efficient than separate MD5 and
+ * SHA-1. It can be useful in implementing SSL 3.0, TLS 1.0 and TLS
+ * 1.1.)
+ *
+ *
+ * ## Multi-Hasher
+ *
+ * An aggregate hasher is provided, that can compute several standard
+ * hash functions in parallel. It uses `br_multihash_context` and a
+ * procedural API. It is configured with the implementations (the vtables)
+ * that it should use; it will then compute all these hash functions in
+ * parallel, on the same input. It is meant to be used in cases when the
+ * hash of an object will be used, but the exact hash function is not
+ * known yet (typically, streamed processing on X.509 certificates).
+ *
+ * Only the standard hash functions (MD5, SHA-1, SHA-224, SHA-256, SHA-384
+ * and SHA-512) are supported by the multi-hasher.
+ *
+ *
+ * ## GHASH
+ *
+ * GHASH is not a generic hash function; it is a _universal_ hash function,
+ * which, as the name does not say, means that it CANNOT be used in most
+ * places where a hash function is needed. GHASH is used within the GCM
+ * encryption mode, to provide the checked integrity functionality.
+ *
+ * A GHASH implementation is basically a function that uses the type defined
+ * in this file under the name `br_ghash`:
+ *
+ * typedef void (*br_ghash)(void *y, const void *h, const void *data, size_t len);
+ *
+ * The `y` pointer refers to a 16-byte value which is used as input, and
+ * receives the output of the GHASH invocation. `h` is a 16-byte secret
+ * value (that serves as key). `data` and `len` define the input data.
+ *
+ * Three GHASH implementations are provided, all constant-time, based on
+ * the use of integer multiplications with appropriate masking to cancel
+ * carry propagation.
+ */
+
+/**
+ * \brief Class type for hash function implementations.
+ *
+ * A `br_hash_class` instance references the methods implementing a hash
+ * function. Constant instances of this structure are defined for each
+ * implemented hash function. Such instances are also called "vtables".
+ *
+ * Vtables are used to support object-oriented programming, as
+ * described on [the BearSSL Web site](https://www.bearssl.org/oop.html).
+ */
+typedef struct br_hash_class_ br_hash_class;
+struct br_hash_class_ {
+ /**
+ * \brief Size (in bytes) of the context structure appropriate for
+ * computing this hash function.
+ */
+ size_t context_size;
+
+ /**
+ * \brief Descriptor word that contains information about the hash
+ * function.
+ *
+ * For each word `xxx` described below, use `BR_HASHDESC_xxx_OFF`
+ * and `BR_HASHDESC_xxx_MASK` to access the specific value, as
+ * follows:
+ *
+ * (hf->desc >> BR_HASHDESC_xxx_OFF) & BR_HASHDESC_xxx_MASK
+ *
+ * The defined elements are:
+ *
+ * - `ID`: the symbolic identifier for the function, as defined
+ * in [TLS](https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1)
+ * (MD5 = 1, SHA-1 = 2,...).
+ *
+ * - `OUT`: hash output size, in bytes.
+ *
+ * - `STATE`: internal running state size, in bytes.
+ *
+ * - `LBLEN`: base-2 logarithm for the internal block size, as
+ * defined for HMAC processing (this is 6 for MD5, SHA-1, SHA-224
+ * and SHA-256, since these functions use 64-byte blocks; for
+ * SHA-384 and SHA-512, this is 7, corresponding to their
+ * 128-byte blocks).
+ *
+ * The descriptor may contain a few other flags.
+ */
+ uint32_t desc;
+
+ /**
+ * \brief Initialisation method.
+ *
+ * This method takes as parameter a pointer to a context area,
+ * that it initialises. The first field of the context is set
+ * to this vtable; other elements are initialised for a new hash
+ * computation.
+ *
+ * \param ctx pointer to (the first field of) the context.
+ */
+ void (*init)(const br_hash_class **ctx);
+
+ /**
+ * \brief Data injection method.
+ *
+ * The `len` bytes starting at address `data` are injected into
+ * the running hash computation incarnated by the specified
+ * context. The context is updated accordingly. It is allowed
+ * to have `len == 0`, in which case `data` is ignored (and could
+ * be `NULL`), and nothing happens.
+ * on the input data.
+ *
+ * \param ctx pointer to (the first field of) the context.
+ * \param data pointer to the first data byte to inject.
+ * \param len number of bytes to inject.
+ */
+ void (*update)(const br_hash_class **ctx, const void *data, size_t len);
+
+ /**
+ * \brief Produce hash output.
+ *
+ * The hash output corresponding to all data bytes injected in the
+ * context since the last `init()` call is computed, and written
+ * in the buffer pointed to by `dst`. The hash output size depends
+ * on the implemented hash function (e.g. 16 bytes for MD5).
+ * The context is _not_ modified by this call, so further bytes
+ * may be afterwards injected to continue the current computation.
+ *
+ * \param ctx pointer to (the first field of) the context.
+ * \param dst destination buffer for the hash output.
+ */
+ void (*out)(const br_hash_class *const *ctx, void *dst);
+
+ /**
+ * \brief Get running state.
+ *
+ * This method saves the current running state into the `dst`
+ * buffer. What constitutes the "running state" depends on the
+ * hash function; for Merkle-Damgård hash functions (like
+ * MD5 or SHA-1), this is the output obtained after processing
+ * each block. The number of bytes injected so far is returned.
+ * The context is not modified by this call.
+ *
+ * \param ctx pointer to (the first field of) the context.
+ * \param dst destination buffer for the state.
+ * \return the injected total byte length.
+ */
+ uint64_t (*state)(const br_hash_class *const *ctx, void *dst);
+
+ /**
+ * \brief Set running state.
+ *
+ * This methods replaces the running state for the function.
+ *
+ * \param ctx pointer to (the first field of) the context.
+ * \param stb source buffer for the state.
+ * \param count injected total byte length.
+ */
+ void (*set_state)(const br_hash_class **ctx,
+ const void *stb, uint64_t count);
+};
+
+#ifndef BR_DOXYGEN_IGNORE
+#define BR_HASHDESC_ID(id) ((uint32_t)(id) << BR_HASHDESC_ID_OFF)
+#define BR_HASHDESC_ID_OFF 0
+#define BR_HASHDESC_ID_MASK 0xFF
+
+#define BR_HASHDESC_OUT(size) ((uint32_t)(size) << BR_HASHDESC_OUT_OFF)
+#define BR_HASHDESC_OUT_OFF 8
+#define BR_HASHDESC_OUT_MASK 0x7F
+
+#define BR_HASHDESC_STATE(size) ((uint32_t)(size) << BR_HASHDESC_STATE_OFF)
+#define BR_HASHDESC_STATE_OFF 15
+#define BR_HASHDESC_STATE_MASK 0xFF
+
+#define BR_HASHDESC_LBLEN(ls) ((uint32_t)(ls) << BR_HASHDESC_LBLEN_OFF)
+#define BR_HASHDESC_LBLEN_OFF 23
+#define BR_HASHDESC_LBLEN_MASK 0x0F
+
+#define BR_HASHDESC_MD_PADDING ((uint32_t)1 << 28)
+#define BR_HASHDESC_MD_PADDING_128 ((uint32_t)1 << 29)
+#define BR_HASHDESC_MD_PADDING_BE ((uint32_t)1 << 30)
+#endif
+
+/*
+ * Specific hash functions.
+ *
+ * Rules for contexts:
+ * -- No interior pointer.
+ * -- No pointer to external dynamically allocated resources.
+ * -- First field is called 'vtable' and is a pointer to a
+ * const-qualified br_hash_class instance (pointer is set by init()).
+ * -- SHA-224 and SHA-256 contexts are identical.
+ * -- SHA-384 and SHA-512 contexts are identical.
+ *
+ * Thus, contexts can be moved and cloned to capture the hash function
+ * current state; and there is no need for any explicit "release" function.
+ */
+
+/**
+ * \brief Symbolic identifier for MD5.
+ */
+#define br_md5_ID 1
+
+/**
+ * \brief MD5 output size (in bytes).
+ */
+#define br_md5_SIZE 16
+
+/**
+ * \brief Constant vtable for MD5.
+ */
+extern const br_hash_class br_md5_vtable;
+
+/**
+ * \brief MD5 context.
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /**
+ * \brief Pointer to vtable for this context.
+ */
+ const br_hash_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ unsigned char buf[64];
+ uint64_t count;
+ uint32_t val[4];
+#endif
+} br_md5_context;
+
+/**
+ * \brief MD5 context initialisation.
+ *
+ * This function initialises or resets a context for a new MD5
+ * computation. It also sets the vtable pointer.
+ *
+ * \param ctx pointer to the context structure.
+ */
+void br_md5_init(br_md5_context *ctx);
+
+/**
+ * \brief Inject some data bytes in a running MD5 computation.
+ *
+ * The provided context is updated with some data bytes. If the number
+ * of bytes (`len`) is zero, then the data pointer (`data`) is ignored
+ * and may be `NULL`, and this function does nothing.
+ *
+ * \param ctx pointer to the context structure.
+ * \param data pointer to the injected data.
+ * \param len injected data length (in bytes).
+ */
+void br_md5_update(br_md5_context *ctx, const void *data, size_t len);
+
+/**
+ * \brief Compute MD5 output.
+ *
+ * The MD5 output for the concatenation of all bytes injected in the
+ * provided context since the last initialisation or reset call, is
+ * computed and written in the buffer pointed to by `out`. The context
+ * itself is not modified, so extra bytes may be injected afterwards
+ * to continue that computation.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the hash output.
+ */
+void br_md5_out(const br_md5_context *ctx, void *out);
+
+/**
+ * \brief Save MD5 running state.
+ *
+ * The running state for MD5 (output of the last internal block
+ * processing) is written in the buffer pointed to by `out`. The
+ * number of bytes injected since the last initialisation or reset
+ * call is returned. The context is not modified.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the running state.
+ * \return the injected total byte length.
+ */
+uint64_t br_md5_state(const br_md5_context *ctx, void *out);
+
+/**
+ * \brief Restore MD5 running state.
+ *
+ * The running state for MD5 is set to the provided values.
+ *
+ * \param ctx pointer to the context structure.
+ * \param stb source buffer for the running state.
+ * \param count the injected total byte length.
+ */
+void br_md5_set_state(br_md5_context *ctx, const void *stb, uint64_t count);
+
+/**
+ * \brief Symbolic identifier for SHA-1.
+ */
+#define br_sha1_ID 2
+
+/**
+ * \brief SHA-1 output size (in bytes).
+ */
+#define br_sha1_SIZE 20
+
+/**
+ * \brief Constant vtable for SHA-1.
+ */
+extern const br_hash_class br_sha1_vtable;
+
+/**
+ * \brief SHA-1 context.
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /**
+ * \brief Pointer to vtable for this context.
+ */
+ const br_hash_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ unsigned char buf[64];
+ uint64_t count;
+ uint32_t val[5];
+#endif
+} br_sha1_context;
+
+/**
+ * \brief SHA-1 context initialisation.
+ *
+ * This function initialises or resets a context for a new SHA-1
+ * computation. It also sets the vtable pointer.
+ *
+ * \param ctx pointer to the context structure.
+ */
+void br_sha1_init(br_sha1_context *ctx);
+
+/**
+ * \brief Inject some data bytes in a running SHA-1 computation.
+ *
+ * The provided context is updated with some data bytes. If the number
+ * of bytes (`len`) is zero, then the data pointer (`data`) is ignored
+ * and may be `NULL`, and this function does nothing.
+ *
+ * \param ctx pointer to the context structure.
+ * \param data pointer to the injected data.
+ * \param len injected data length (in bytes).
+ */
+void br_sha1_update(br_sha1_context *ctx, const void *data, size_t len);
+
+/**
+ * \brief Compute SHA-1 output.
+ *
+ * The SHA-1 output for the concatenation of all bytes injected in the
+ * provided context since the last initialisation or reset call, is
+ * computed and written in the buffer pointed to by `out`. The context
+ * itself is not modified, so extra bytes may be injected afterwards
+ * to continue that computation.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the hash output.
+ */
+void br_sha1_out(const br_sha1_context *ctx, void *out);
+
+/**
+ * \brief Save SHA-1 running state.
+ *
+ * The running state for SHA-1 (output of the last internal block
+ * processing) is written in the buffer pointed to by `out`. The
+ * number of bytes injected since the last initialisation or reset
+ * call is returned. The context is not modified.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the running state.
+ * \return the injected total byte length.
+ */
+uint64_t br_sha1_state(const br_sha1_context *ctx, void *out);
+
+/**
+ * \brief Restore SHA-1 running state.
+ *
+ * The running state for SHA-1 is set to the provided values.
+ *
+ * \param ctx pointer to the context structure.
+ * \param stb source buffer for the running state.
+ * \param count the injected total byte length.
+ */
+void br_sha1_set_state(br_sha1_context *ctx, const void *stb, uint64_t count);
+
+/**
+ * \brief Symbolic identifier for SHA-224.
+ */
+#define br_sha224_ID 3
+
+/**
+ * \brief SHA-224 output size (in bytes).
+ */
+#define br_sha224_SIZE 28
+
+/**
+ * \brief Constant vtable for SHA-224.
+ */
+extern const br_hash_class br_sha224_vtable;
+
+/**
+ * \brief SHA-224 context.
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /**
+ * \brief Pointer to vtable for this context.
+ */
+ const br_hash_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ unsigned char buf[64];
+ uint64_t count;
+ uint32_t val[8];
+#endif
+} br_sha224_context;
+
+/**
+ * \brief SHA-224 context initialisation.
+ *
+ * This function initialises or resets a context for a new SHA-224
+ * computation. It also sets the vtable pointer.
+ *
+ * \param ctx pointer to the context structure.
+ */
+void br_sha224_init(br_sha224_context *ctx);
+
+/**
+ * \brief Inject some data bytes in a running SHA-224 computation.
+ *
+ * The provided context is updated with some data bytes. If the number
+ * of bytes (`len`) is zero, then the data pointer (`data`) is ignored
+ * and may be `NULL`, and this function does nothing.
+ *
+ * \param ctx pointer to the context structure.
+ * \param data pointer to the injected data.
+ * \param len injected data length (in bytes).
+ */
+void br_sha224_update(br_sha224_context *ctx, const void *data, size_t len);
+
+/**
+ * \brief Compute SHA-224 output.
+ *
+ * The SHA-224 output for the concatenation of all bytes injected in the
+ * provided context since the last initialisation or reset call, is
+ * computed and written in the buffer pointed to by `out`. The context
+ * itself is not modified, so extra bytes may be injected afterwards
+ * to continue that computation.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the hash output.
+ */
+void br_sha224_out(const br_sha224_context *ctx, void *out);
+
+/**
+ * \brief Save SHA-224 running state.
+ *
+ * The running state for SHA-224 (output of the last internal block
+ * processing) is written in the buffer pointed to by `out`. The
+ * number of bytes injected since the last initialisation or reset
+ * call is returned. The context is not modified.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the running state.
+ * \return the injected total byte length.
+ */
+uint64_t br_sha224_state(const br_sha224_context *ctx, void *out);
+
+/**
+ * \brief Restore SHA-224 running state.
+ *
+ * The running state for SHA-224 is set to the provided values.
+ *
+ * \param ctx pointer to the context structure.
+ * \param stb source buffer for the running state.
+ * \param count the injected total byte length.
+ */
+void br_sha224_set_state(br_sha224_context *ctx,
+ const void *stb, uint64_t count);
+
+/**
+ * \brief Symbolic identifier for SHA-256.
+ */
+#define br_sha256_ID 4
+
+/**
+ * \brief SHA-256 output size (in bytes).
+ */
+#define br_sha256_SIZE 32
+
+/**
+ * \brief Constant vtable for SHA-256.
+ */
+extern const br_hash_class br_sha256_vtable;
+
+#ifdef BR_DOXYGEN_IGNORE
+/**
+ * \brief SHA-256 context.
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /**
+ * \brief Pointer to vtable for this context.
+ */
+ const br_hash_class *vtable;
+} br_sha256_context;
+#else
+typedef br_sha224_context br_sha256_context;
+#endif
+
+/**
+ * \brief SHA-256 context initialisation.
+ *
+ * This function initialises or resets a context for a new SHA-256
+ * computation. It also sets the vtable pointer.
+ *
+ * \param ctx pointer to the context structure.
+ */
+void br_sha256_init(br_sha256_context *ctx);
+
+#ifdef BR_DOXYGEN_IGNORE
+/**
+ * \brief Inject some data bytes in a running SHA-256 computation.
+ *
+ * The provided context is updated with some data bytes. If the number
+ * of bytes (`len`) is zero, then the data pointer (`data`) is ignored
+ * and may be `NULL`, and this function does nothing.
+ *
+ * \param ctx pointer to the context structure.
+ * \param data pointer to the injected data.
+ * \param len injected data length (in bytes).
+ */
+void br_sha256_update(br_sha256_context *ctx, const void *data, size_t len);
+#else
+#define br_sha256_update br_sha224_update
+#endif
+
+/**
+ * \brief Compute SHA-256 output.
+ *
+ * The SHA-256 output for the concatenation of all bytes injected in the
+ * provided context since the last initialisation or reset call, is
+ * computed and written in the buffer pointed to by `out`. The context
+ * itself is not modified, so extra bytes may be injected afterwards
+ * to continue that computation.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the hash output.
+ */
+void br_sha256_out(const br_sha256_context *ctx, void *out);
+
+#if BR_DOXYGEN_IGNORE
+/**
+ * \brief Save SHA-256 running state.
+ *
+ * The running state for SHA-256 (output of the last internal block
+ * processing) is written in the buffer pointed to by `out`. The
+ * number of bytes injected since the last initialisation or reset
+ * call is returned. The context is not modified.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the running state.
+ * \return the injected total byte length.
+ */
+uint64_t br_sha256_state(const br_sha256_context *ctx, void *out);
+#else
+#define br_sha256_state br_sha224_state
+#endif
+
+#if BR_DOXYGEN_IGNORE
+/**
+ * \brief Restore SHA-256 running state.
+ *
+ * The running state for SHA-256 is set to the provided values.
+ *
+ * \param ctx pointer to the context structure.
+ * \param stb source buffer for the running state.
+ * \param count the injected total byte length.
+ */
+void br_sha256_set_state(br_sha256_context *ctx,
+ const void *stb, uint64_t count);
+#else
+#define br_sha256_set_state br_sha224_set_state
+#endif
+
+/**
+ * \brief Symbolic identifier for SHA-384.
+ */
+#define br_sha384_ID 5
+
+/**
+ * \brief SHA-384 output size (in bytes).
+ */
+#define br_sha384_SIZE 48
+
+/**
+ * \brief Constant vtable for SHA-384.
+ */
+extern const br_hash_class br_sha384_vtable;
+
+/**
+ * \brief SHA-384 context.
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /**
+ * \brief Pointer to vtable for this context.
+ */
+ const br_hash_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ unsigned char buf[128];
+ uint64_t count;
+ uint64_t val[8];
+#endif
+} br_sha384_context;
+
+/**
+ * \brief SHA-384 context initialisation.
+ *
+ * This function initialises or resets a context for a new SHA-384
+ * computation. It also sets the vtable pointer.
+ *
+ * \param ctx pointer to the context structure.
+ */
+void br_sha384_init(br_sha384_context *ctx);
+
+/**
+ * \brief Inject some data bytes in a running SHA-384 computation.
+ *
+ * The provided context is updated with some data bytes. If the number
+ * of bytes (`len`) is zero, then the data pointer (`data`) is ignored
+ * and may be `NULL`, and this function does nothing.
+ *
+ * \param ctx pointer to the context structure.
+ * \param data pointer to the injected data.
+ * \param len injected data length (in bytes).
+ */
+void br_sha384_update(br_sha384_context *ctx, const void *data, size_t len);
+
+/**
+ * \brief Compute SHA-384 output.
+ *
+ * The SHA-384 output for the concatenation of all bytes injected in the
+ * provided context since the last initialisation or reset call, is
+ * computed and written in the buffer pointed to by `out`. The context
+ * itself is not modified, so extra bytes may be injected afterwards
+ * to continue that computation.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the hash output.
+ */
+void br_sha384_out(const br_sha384_context *ctx, void *out);
+
+/**
+ * \brief Save SHA-384 running state.
+ *
+ * The running state for SHA-384 (output of the last internal block
+ * processing) is written in the buffer pointed to by `out`. The
+ * number of bytes injected since the last initialisation or reset
+ * call is returned. The context is not modified.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the running state.
+ * \return the injected total byte length.
+ */
+uint64_t br_sha384_state(const br_sha384_context *ctx, void *out);
+
+/**
+ * \brief Restore SHA-384 running state.
+ *
+ * The running state for SHA-384 is set to the provided values.
+ *
+ * \param ctx pointer to the context structure.
+ * \param stb source buffer for the running state.
+ * \param count the injected total byte length.
+ */
+void br_sha384_set_state(br_sha384_context *ctx,
+ const void *stb, uint64_t count);
+
+/**
+ * \brief Symbolic identifier for SHA-512.
+ */
+#define br_sha512_ID 6
+
+/**
+ * \brief SHA-512 output size (in bytes).
+ */
+#define br_sha512_SIZE 64
+
+/**
+ * \brief Constant vtable for SHA-512.
+ */
+extern const br_hash_class br_sha512_vtable;
+
+#ifdef BR_DOXYGEN_IGNORE
+/**
+ * \brief SHA-512 context.
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /**
+ * \brief Pointer to vtable for this context.
+ */
+ const br_hash_class *vtable;
+} br_sha512_context;
+#else
+typedef br_sha384_context br_sha512_context;
+#endif
+
+/**
+ * \brief SHA-512 context initialisation.
+ *
+ * This function initialises or resets a context for a new SHA-512
+ * computation. It also sets the vtable pointer.
+ *
+ * \param ctx pointer to the context structure.
+ */
+void br_sha512_init(br_sha512_context *ctx);
+
+#ifdef BR_DOXYGEN_IGNORE
+/**
+ * \brief Inject some data bytes in a running SHA-512 computation.
+ *
+ * The provided context is updated with some data bytes. If the number
+ * of bytes (`len`) is zero, then the data pointer (`data`) is ignored
+ * and may be `NULL`, and this function does nothing.
+ *
+ * \param ctx pointer to the context structure.
+ * \param data pointer to the injected data.
+ * \param len injected data length (in bytes).
+ */
+void br_sha512_update(br_sha512_context *ctx, const void *data, size_t len);
+#else
+#define br_sha512_update br_sha384_update
+#endif
+
+/**
+ * \brief Compute SHA-512 output.
+ *
+ * The SHA-512 output for the concatenation of all bytes injected in the
+ * provided context since the last initialisation or reset call, is
+ * computed and written in the buffer pointed to by `out`. The context
+ * itself is not modified, so extra bytes may be injected afterwards
+ * to continue that computation.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the hash output.
+ */
+void br_sha512_out(const br_sha512_context *ctx, void *out);
+
+#ifdef BR_DOXYGEN_IGNORE
+/**
+ * \brief Save SHA-512 running state.
+ *
+ * The running state for SHA-512 (output of the last internal block
+ * processing) is written in the buffer pointed to by `out`. The
+ * number of bytes injected since the last initialisation or reset
+ * call is returned. The context is not modified.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the running state.
+ * \return the injected total byte length.
+ */
+uint64_t br_sha512_state(const br_sha512_context *ctx, void *out);
+#else
+#define br_sha512_state br_sha384_state
+#endif
+
+#ifdef BR_DOXYGEN_IGNORE
+/**
+ * \brief Restore SHA-512 running state.
+ *
+ * The running state for SHA-512 is set to the provided values.
+ *
+ * \param ctx pointer to the context structure.
+ * \param stb source buffer for the running state.
+ * \param count the injected total byte length.
+ */
+void br_sha512_set_state(br_sha512_context *ctx,
+ const void *stb, uint64_t count);
+#else
+#define br_sha512_set_state br_sha384_set_state
+#endif
+
+/*
+ * "md5sha1" is a special hash function that computes both MD5 and SHA-1
+ * on the same input, and produces a 36-byte output (MD5 and SHA-1
+ * concatenation, in that order). State size is also 36 bytes.
+ */
+
+/**
+ * \brief Symbolic identifier for MD5+SHA-1.
+ *
+ * MD5+SHA-1 is the concatenation of MD5 and SHA-1, computed over the
+ * same input. It is not one of the functions identified in TLS, so
+ * we give it a symbolic identifier of value 0.
+ */
+#define br_md5sha1_ID 0
+
+/**
+ * \brief MD5+SHA-1 output size (in bytes).
+ */
+#define br_md5sha1_SIZE 36
+
+/**
+ * \brief Constant vtable for MD5+SHA-1.
+ */
+extern const br_hash_class br_md5sha1_vtable;
+
+/**
+ * \brief MD5+SHA-1 context.
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /**
+ * \brief Pointer to vtable for this context.
+ */
+ const br_hash_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ unsigned char buf[64];
+ uint64_t count;
+ uint32_t val_md5[4];
+ uint32_t val_sha1[5];
+#endif
+} br_md5sha1_context;
+
+/**
+ * \brief MD5+SHA-1 context initialisation.
+ *
+ * This function initialises or resets a context for a new SHA-512
+ * computation. It also sets the vtable pointer.
+ *
+ * \param ctx pointer to the context structure.
+ */
+void br_md5sha1_init(br_md5sha1_context *ctx);
+
+/**
+ * \brief Inject some data bytes in a running MD5+SHA-1 computation.
+ *
+ * The provided context is updated with some data bytes. If the number
+ * of bytes (`len`) is zero, then the data pointer (`data`) is ignored
+ * and may be `NULL`, and this function does nothing.
+ *
+ * \param ctx pointer to the context structure.
+ * \param data pointer to the injected data.
+ * \param len injected data length (in bytes).
+ */
+void br_md5sha1_update(br_md5sha1_context *ctx, const void *data, size_t len);
+
+/**
+ * \brief Compute MD5+SHA-1 output.
+ *
+ * The MD5+SHA-1 output for the concatenation of all bytes injected in the
+ * provided context since the last initialisation or reset call, is
+ * computed and written in the buffer pointed to by `out`. The context
+ * itself is not modified, so extra bytes may be injected afterwards
+ * to continue that computation.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the hash output.
+ */
+void br_md5sha1_out(const br_md5sha1_context *ctx, void *out);
+
+/**
+ * \brief Save MD5+SHA-1 running state.
+ *
+ * The running state for MD5+SHA-1 (output of the last internal block
+ * processing) is written in the buffer pointed to by `out`. The
+ * number of bytes injected since the last initialisation or reset
+ * call is returned. The context is not modified.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the running state.
+ * \return the injected total byte length.
+ */
+uint64_t br_md5sha1_state(const br_md5sha1_context *ctx, void *out);
+
+/**
+ * \brief Restore MD5+SHA-1 running state.
+ *
+ * The running state for MD5+SHA-1 is set to the provided values.
+ *
+ * \param ctx pointer to the context structure.
+ * \param stb source buffer for the running state.
+ * \param count the injected total byte length.
+ */
+void br_md5sha1_set_state(br_md5sha1_context *ctx,
+ const void *stb, uint64_t count);
+
+/**
+ * \brief Aggregate context for configurable hash function support.
+ *
+ * The `br_hash_compat_context` type is a type which is large enough to
+ * serve as context for all standard hash functions defined above.
+ */
+typedef union {
+ const br_hash_class *vtable;
+ br_md5_context md5;
+ br_sha1_context sha1;
+ br_sha224_context sha224;
+ br_sha256_context sha256;
+ br_sha384_context sha384;
+ br_sha512_context sha512;
+ br_md5sha1_context md5sha1;
+} br_hash_compat_context;
+
+/*
+ * The multi-hasher is a construct that handles hashing of the same input
+ * data with several hash functions, with a single shared input buffer.
+ * It can handle MD5, SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512
+ * simultaneously, though which functions are activated depends on
+ * the set implementation pointers.
+ */
+
+/**
+ * \brief Multi-hasher context structure.
+ *
+ * The multi-hasher runs up to six hash functions in the standard TLS list
+ * (MD5, SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512) in parallel, over
+ * the same input.
+ *
+ * The multi-hasher does _not_ follow the OOP structure with a vtable.
+ * Instead, it is configured with the vtables of the hash functions it
+ * should run. Structure fields are not supposed to be accessed directly.
+ */
+typedef struct {
+#ifndef BR_DOXYGEN_IGNORE
+ unsigned char buf[128];
+ uint64_t count;
+ uint32_t val_32[25];
+ uint64_t val_64[16];
+ const br_hash_class *impl[6];
+#endif
+} br_multihash_context;
+
+/**
+ * \brief Clear a multi-hasher context.
+ *
+ * This should always be called once on a given context, _before_ setting
+ * the implementation pointers.
+ *
+ * \param ctx the multi-hasher context.
+ */
+void br_multihash_zero(br_multihash_context *ctx);
+
+/**
+ * \brief Set a hash function implementation.
+ *
+ * Implementations shall be set _after_ clearing the context (with
+ * `br_multihash_zero()`) but _before_ initialising the computation
+ * (with `br_multihash_init()`). The hash function implementation
+ * MUST be one of the standard hash functions (MD5, SHA-1, SHA-224,
+ * SHA-256, SHA-384 or SHA-512); it may also be `NULL` to remove
+ * an implementation from the multi-hasher.
+ *
+ * \param ctx the multi-hasher context.
+ * \param id the hash function symbolic identifier.
+ * \param impl the hash function vtable, or `NULL`.
+ */
+static inline void
+br_multihash_setimpl(br_multihash_context *ctx,
+ int id, const br_hash_class *impl)
+{
+ /*
+ * This code relies on hash functions ID being values 1 to 6,
+ * in the MD5 to SHA-512 order.
+ */
+ ctx->impl[id - 1] = impl;
+}
+
+/**
+ * \brief Get a hash function implementation.
+ *
+ * This function returns the currently configured vtable for a given
+ * hash function (by symbolic ID). If no such function was configured in
+ * the provided multi-hasher context, then this function returns `NULL`.
+ *
+ * \param ctx the multi-hasher context.
+ * \param id the hash function symbolic identifier.
+ * \return the hash function vtable, or `NULL`.
+ */
+static inline const br_hash_class *
+br_multihash_getimpl(const br_multihash_context *ctx, int id)
+{
+ return ctx->impl[id - 1];
+}
+
+/**
+ * \brief Reset a multi-hasher context.
+ *
+ * This function prepares the context for a new hashing computation,
+ * for all implementations configured at that point.
+ *
+ * \param ctx the multi-hasher context.
+ */
+void br_multihash_init(br_multihash_context *ctx);
+
+/**
+ * \brief Inject some data bytes in a running multi-hashing computation.
+ *
+ * The provided context is updated with some data bytes. If the number
+ * of bytes (`len`) is zero, then the data pointer (`data`) is ignored
+ * and may be `NULL`, and this function does nothing.
+ *
+ * \param ctx pointer to the context structure.
+ * \param data pointer to the injected data.
+ * \param len injected data length (in bytes).
+ */
+void br_multihash_update(br_multihash_context *ctx,
+ const void *data, size_t len);
+
+/**
+ * \brief Compute a hash output from a multi-hasher.
+ *
+ * The hash output for the concatenation of all bytes injected in the
+ * provided context since the last initialisation or reset call, is
+ * computed and written in the buffer pointed to by `dst`. The hash
+ * function to use is identified by `id` and must be one of the standard
+ * hash functions. If that hash function was indeed configured in the
+ * multi-hasher context, the corresponding hash value is written in
+ * `dst` and its length (in bytes) is returned. If the hash function
+ * was _not_ configured, then nothing is written in `dst` and 0 is
+ * returned.
+ *
+ * The context itself is not modified, so extra bytes may be injected
+ * afterwards to continue the hash computations.
+ *
+ * \param ctx pointer to the context structure.
+ * \param id the hash function symbolic identifier.
+ * \param dst destination buffer for the hash output.
+ * \return the hash output length (in bytes), or 0.
+ */
+size_t br_multihash_out(const br_multihash_context *ctx, int id, void *dst);
+
+/**
+ * \brief Type for a GHASH implementation.
+ *
+ * GHASH is a sort of keyed hash meant to be used to implement GCM in
+ * combination with a block cipher (with 16-byte blocks).
+ *
+ * The `y` array has length 16 bytes and is used for input and output; in
+ * a complete GHASH run, it starts with an all-zero value. `h` is a 16-byte
+ * value that serves as key (it is derived from the encryption key in GCM,
+ * using the block cipher). The data length (`len`) is expressed in bytes.
+ * The `y` array is updated.
+ *
+ * If the data length is not a multiple of 16, then the data is implicitly
+ * padded with zeros up to the next multiple of 16. Thus, when using GHASH
+ * in GCM, this method may be called twice, for the associated data and
+ * for the ciphertext, respectively; the zero-padding implements exactly
+ * the GCM rules.
+ *
+ * \param y the array to update.
+ * \param h the GHASH key.
+ * \param data the input data (may be `NULL` if `len` is zero).
+ * \param len the input data length (in bytes).
+ */
+typedef void (*br_ghash)(void *y, const void *h, const void *data, size_t len);
+
+/**
+ * \brief GHASH implementation using multiplications (mixed 32-bit).
+ *
+ * This implementation uses multiplications of 32-bit values, with a
+ * 64-bit result. It is constant-time (if multiplications are
+ * constant-time).
+ *
+ * \param y the array to update.
+ * \param h the GHASH key.
+ * \param data the input data (may be `NULL` if `len` is zero).
+ * \param len the input data length (in bytes).
+ */
+void br_ghash_ctmul(void *y, const void *h, const void *data, size_t len);
+
+/**
+ * \brief GHASH implementation using multiplications (strict 32-bit).
+ *
+ * This implementation uses multiplications of 32-bit values, with a
+ * 32-bit result. It is usually somewhat slower than `br_ghash_ctmul()`,
+ * but it is expected to be faster on architectures for which the
+ * 32-bit multiplication opcode does not yield the upper 32 bits of the
+ * product. It is constant-time (if multiplications are constant-time).
+ *
+ * \param y the array to update.
+ * \param h the GHASH key.
+ * \param data the input data (may be `NULL` if `len` is zero).
+ * \param len the input data length (in bytes).
+ */
+void br_ghash_ctmul32(void *y, const void *h, const void *data, size_t len);
+
+/**
+ * \brief GHASH implementation using multiplications (64-bit).
+ *
+ * This implementation uses multiplications of 64-bit values, with a
+ * 64-bit result. It is constant-time (if multiplications are
+ * constant-time). It is substantially faster than `br_ghash_ctmul()`
+ * and `br_ghash_ctmul32()` on most 64-bit architectures.
+ *
+ * \param y the array to update.
+ * \param h the GHASH key.
+ * \param data the input data (may be `NULL` if `len` is zero).
+ * \param len the input data length (in bytes).
+ */
+void br_ghash_ctmul64(void *y, const void *h, const void *data, size_t len);
+
+/**
+ * \brief GHASH implementation using the `pclmulqdq` opcode (part of the
+ * AES-NI instructions).
+ *
+ * This implementation is available only on x86 platforms where the
+ * compiler supports the relevant intrinsic functions. Even if the
+ * compiler supports these functions, the local CPU might not support
+ * the `pclmulqdq` opcode, meaning that a call will fail with an
+ * illegal instruction exception. To safely obtain a pointer to this
+ * function when supported (or 0 otherwise), use `br_ghash_pclmul_get()`.
+ *
+ * \param y the array to update.
+ * \param h the GHASH key.
+ * \param data the input data (may be `NULL` if `len` is zero).
+ * \param len the input data length (in bytes).
+ */
+void br_ghash_pclmul(void *y, const void *h, const void *data, size_t len);
+
+/**
+ * \brief Obtain the `pclmul` GHASH implementation, if available.
+ *
+ * If the `pclmul` implementation was compiled in the library (depending
+ * on the compiler abilities) _and_ the local CPU appears to support the
+ * opcode, then this function will return a pointer to the
+ * `br_ghash_pclmul()` function. Otherwise, it will return `0`.
+ *
+ * \return the `pclmul` GHASH implementation, or `0`.
+ */
+br_ghash br_ghash_pclmul_get(void);
+
+/**
+ * \brief GHASH implementation using the POWER8 opcodes.
+ *
+ * This implementation is available only on POWER8 platforms (and later).
+ * To safely obtain a pointer to this function when supported (or 0
+ * otherwise), use `br_ghash_pwr8_get()`.
+ *
+ * \param y the array to update.
+ * \param h the GHASH key.
+ * \param data the input data (may be `NULL` if `len` is zero).
+ * \param len the input data length (in bytes).
+ */
+void br_ghash_pwr8(void *y, const void *h, const void *data, size_t len);
+
+/**
+ * \brief Obtain the `pwr8` GHASH implementation, if available.
+ *
+ * If the `pwr8` implementation was compiled in the library (depending
+ * on the compiler abilities) _and_ the local CPU appears to support the
+ * opcode, then this function will return a pointer to the
+ * `br_ghash_pwr8()` function. Otherwise, it will return `0`.
+ *
+ * \return the `pwr8` GHASH implementation, or `0`.
+ */
+br_ghash br_ghash_pwr8_get(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/inc/bearssl_hmac.h b/inc/bearssl_hmac.h
new file mode 100644
index 000000000000..4dc01ca31203
--- /dev/null
+++ b/inc/bearssl_hmac.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef BR_BEARSSL_HMAC_H__
+#define BR_BEARSSL_HMAC_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "bearssl_hash.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file bearssl_hmac.h
+ *
+ * # HMAC
+ *
+ * HMAC is initialized with a key and an underlying hash function; it
+ * then fills a "key context". That context contains the processed
+ * key.
+ *
+ * With the key context, a HMAC context can be initialized to process
+ * the input bytes and obtain the MAC output. The key context is not
+ * modified during that process, and can be reused.
+ *
+ * IMPORTANT: HMAC shall be used only with functions that have the
+ * following properties:
+ *
+ * - hash output size does not exceed 64 bytes;
+ * - hash internal state size does not exceed 64 bytes;
+ * - internal block length is a power of 2 between 16 and 256 bytes.
+ */
+
+/**
+ * \brief HMAC key context.
+ *
+ * The HMAC key context is initialised with a hash function implementation
+ * and a secret key. Contents are opaque (callers should not access them
+ * directly). The caller is responsible for allocating the context where
+ * appropriate. Context initialisation and usage incurs no dynamic
+ * allocation, so there is no release function.
+ */
+typedef struct {
+#ifndef BR_DOXYGEN_IGNORE
+ const br_hash_class *dig_vtable;
+ unsigned char ksi[64], kso[64];
+#endif
+} br_hmac_key_context;
+
+/**
+ * \brief HMAC key context initialisation.
+ *
+ * Initialise the key context with the provided key, using the hash function
+ * identified by `digest_vtable`. This supports arbitrary key lengths.
+ *
+ * \param kc HMAC key context to initialise.
+ * \param digest_vtable pointer to the hash function implementation vtable.
+ * \param key pointer to the HMAC secret key.
+ * \param key_len HMAC secret key length (in bytes).
+ */
+void br_hmac_key_init(br_hmac_key_context *kc,
+ const br_hash_class *digest_vtable, const void *key, size_t key_len);
+
+/*
+ * \brief Get the underlying hash function.
+ *
+ * This function returns a pointer to the implementation vtable of the
+ * hash function used for this HMAC key context.
+ *
+ * \param kc HMAC key context.
+ * \return the hash function implementation.
+ */
+static inline const br_hash_class *br_hmac_key_get_digest(
+ const br_hmac_key_context *kc)
+{
+ return kc->dig_vtable;
+}
+
+/**
+ * \brief HMAC computation context.
+ *
+ * The HMAC computation context maintains the state for a single HMAC
+ * computation. It is modified as input bytes are injected. The context
+ * is caller-allocated and has no release function since it does not
+ * dynamically allocate external resources. Its contents are opaque.
+ */
+typedef struct {
+#ifndef BR_DOXYGEN_IGNORE
+ br_hash_compat_context dig;
+ unsigned char kso[64];
+ size_t out_len;
+#endif
+} br_hmac_context;
+
+/**
+ * \brief HMAC computation initialisation.
+ *
+ * Initialise a HMAC context with a key context. The key context is
+ * unmodified. Relevant data from the key context is immediately copied;
+ * the key context can thus be independently reused, modified or released
+ * without impacting this HMAC computation.
+ *
+ * An explicit output length can be specified; the actual output length
+ * will be the minimum of that value and the natural HMAC output length.
+ * If `out_len` is 0, then the natural HMAC output length is selected. The
+ * "natural output length" is the output length of the underlying hash
+ * function.
+ *
+ * \param ctx HMAC context to initialise.
+ * \param kc HMAC key context (already initialised with the key).
+ * \param out_len HMAC output length (0 to select "natural length").
+ */
+void br_hmac_init(br_hmac_context *ctx,
+ const br_hmac_key_context *kc, size_t out_len);
+
+/**
+ * \brief Get the HMAC output size.
+ *
+ * The HMAC output size is the number of bytes that will actually be
+ * produced with `br_hmac_out()` with the provided context. This function
+ * MUST NOT be called on a non-initialised HMAC computation context.
+ * The returned value is the minimum of the HMAC natural length (output
+ * size of the underlying hash function) and the `out_len` parameter which
+ * was used with the last `br_hmac_init()` call on that context (if the
+ * initialisation `out_len` parameter was 0, then this function will
+ * return the HMAC natural length).
+ *
+ * \param ctx the (already initialised) HMAC computation context.
+ * \return the HMAC actual output size.
+ */
+static inline size_t
+br_hmac_size(br_hmac_context *ctx)
+{
+ return ctx->out_len;
+}
+
+/*
+ * \brief Get the underlying hash function.
+ *
+ * This function returns a pointer to the implementation vtable of the
+ * hash function used for this HMAC context.
+ *
+ * \param hc HMAC context.
+ * \return the hash function implementation.
+ */
+static inline const br_hash_class *br_hmac_get_digest(
+ const br_hmac_context *hc)
+{
+ return hc->dig.vtable;
+}
+
+/**
+ * \brief Inject some bytes in HMAC.
+ *
+ * The provided `len` bytes are injected as extra input in the HMAC
+ * computation incarnated by the `ctx` HMAC context. It is acceptable
+ * that `len` is zero, in which case `data` is ignored (and may be
+ * `NULL`) and this function does nothing.
+ */
+void br_hmac_update(br_hmac_context *ctx, const void *data, size_t len);
+
+/**
+ * \brief Compute the HMAC output.
+ *
+ * The destination buffer MUST be large enough to accommodate the result;
+ * its length is at most the "natural length" of HMAC (i.e. the output
+ * length of the underlying hash function). The context is NOT modified;
+ * further bytes may be processed. Thus, "partial HMAC" values can be
+ * efficiently obtained.
+ *
+ * Returned value is the output length (in bytes).
+ *
+ * \param ctx HMAC computation context.
+ * \param out destination buffer for the HMAC output.
+ * \return the produced value length (in bytes).
+ */
+size_t br_hmac_out(const br_hmac_context *ctx, void *out);
+
+/**
+ * \brief Constant-time HMAC computation.
+ *
+ * This function compute the HMAC output in constant time. Some extra
+ * input bytes are processed, then the output is computed. The extra
+ * input consists in the `len` bytes pointed to by `data`. The `len`
+ * parameter must lie between `min_len` and `max_len` (inclusive);
+ * `max_len` bytes are actually read from `data`. Computing time (and
+ * memory access pattern) will not depend upon the data byte contents or
+ * the value of `len`.
+ *
+ * The output is written in the `out` buffer, that MUST be large enough
+ * to receive it.
+ *
+ * The difference `max_len - min_len` MUST be less than 2<sup>30</sup>
+ * (i.e. about one gigabyte).
+ *
+ * This function computes the output properly only if the underlying
+ * hash function uses MD padding (i.e. MD5, SHA-1, SHA-224, SHA-256,
+ * SHA-384 or SHA-512).
+ *
+ * The provided context is NOT modified.
+ *
+ * \param ctx the (already initialised) HMAC computation context.
+ * \param data the extra input bytes.
+ * \param len the extra input length (in bytes).
+ * \param min_len minimum extra input length (in bytes).
+ * \param max_len maximum extra input length (in bytes).
+ * \param out destination buffer for the HMAC output.
+ * \return the produced value length (in bytes).
+ */
+size_t br_hmac_outCT(const br_hmac_context *ctx,
+ const void *data, size_t len, size_t min_len, size_t max_len,
+ void *out);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/inc/bearssl_kdf.h b/inc/bearssl_kdf.h
new file mode 100644
index 000000000000..955b84367ee5
--- /dev/null
+++ b/inc/bearssl_kdf.h
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef BR_BEARSSL_KDF_H__
+#define BR_BEARSSL_KDF_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "bearssl_hash.h"
+#include "bearssl_hmac.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file bearssl_kdf.h
+ *
+ * # Key Derivation Functions
+ *
+ * KDF are functions that takes a variable length input, and provide a
+ * variable length output, meant to be used to derive subkeys from a
+ * master key.
+ *
+ * ## HKDF
+ *
+ * HKDF is a KDF defined by [RFC 5869](https://tools.ietf.org/html/rfc5869).
+ * It is based on HMAC, itself using an underlying hash function. Any
+ * hash function can be used, as long as it is compatible with the rules
+ * for the HMAC implementation (i.e. output size is 64 bytes or less, hash
+ * internal state size is 64 bytes or less, and the internal block length is
+ * a power of 2 between 16 and 256 bytes). HKDF has two phases:
+ *
+ * - HKDF-Extract: the input data in ingested, along with a "salt" value.
+ *
+ * - HKDF-Expand: the output is produced, from the result of processing
+ * the input and salt, and using an extra non-secret parameter called
+ * "info".
+ *
+ * The "salt" and "info" strings are non-secret and can be empty. Their role
+ * is normally to bind the input and output, respectively, to conventional
+ * identifiers that qualifu them within the used protocol or application.
+ *
+ * The implementation defined in this file uses the following functions:
+ *
+ * - `br_hkdf_init()`: initialize an HKDF context, with a hash function,
+ * and the salt. This starts the HKDF-Extract process.
+ *
+ * - `br_hkdf_inject()`: inject more input bytes. This function may be
+ * called repeatedly if the input data is provided by chunks.
+ *
+ * - `br_hkdf_flip()`: end the HKDF-Extract process, and start the
+ * HKDF-Expand process.
+ *
+ * - `br_hkdf_produce()`: get the next bytes of output. This function
+ * may be called several times to obtain the full output by chunks.
+ * For correct HKDF processing, the same "info" string must be
+ * provided for each call.
+ *
+ * Note that the HKDF total output size (the number of bytes that
+ * HKDF-Expand is willing to produce) is limited: if the hash output size
+ * is _n_ bytes, then the maximum output size is _255*n_.
+ *
+ * ## SHAKE
+ *
+ * SHAKE is defined in
+ * [FIPS 202](https://csrc.nist.gov/publications/detail/fips/202/final)
+ * under two versions: SHAKE128 and SHAKE256, offering an alleged
+ * "security level" of 128 and 256 bits, respectively (SHAKE128 is
+ * about 20 to 25% faster than SHAKE256). SHAKE internally relies on
+ * the Keccak family of sponge functions, not on any externally provided
+ * hash function. Contrary to HKDF, SHAKE does not have a concept of
+ * either a "salt" or an "info" string. The API consists in four
+ * functions:
+ *
+ * - `br_shake_init()`: initialize a SHAKE context for a given
+ * security level.
+ *
+ * - `br_shake_inject()`: inject more input bytes. This function may be
+ * called repeatedly if the input data is provided by chunks.
+ *
+ * - `br_shake_flip()`: end the data injection process, and start the
+ * data production process.
+ *
+ * - `br_shake_produce()`: get the next bytes of output. This function
+ * may be called several times to obtain the full output by chunks.
+ */
+
+/**
+ * \brief HKDF context.
+ *
+ * The HKDF context is initialized with a hash function implementation
+ * and a salt value. Contents are opaque (callers should not access them
+ * directly). The caller is responsible for allocating the context where
+ * appropriate. Context initialisation and usage incurs no dynamic
+ * allocation, so there is no release function.
+ */
+typedef struct {
+#ifndef BR_DOXYGEN_IGNORE
+ union {
+ br_hmac_context hmac_ctx;
+ br_hmac_key_context prk_ctx;
+ } u;
+ unsigned char buf[64];
+ size_t ptr;
+ size_t dig_len;
+ unsigned chunk_num;
+#endif
+} br_hkdf_context;
+
+/**
+ * \brief HKDF context initialization.
+ *
+ * The underlying hash function and salt value are provided. Arbitrary
+ * salt lengths can be used.
+ *
+ * HKDF makes a difference between a salt of length zero, and an
+ * absent salt (the latter being equivalent to a salt consisting of
+ * bytes of value zero, of the same length as the hash function output).
+ * If `salt_len` is zero, then this function assumes that the salt is
+ * present but of length zero. To specify an _absent_ salt, use
+ * `BR_HKDF_NO_SALT` as `salt` parameter (`salt_len` is then ignored).
+ *
+ * \param hc HKDF context to initialise.
+ * \param digest_vtable pointer to the hash function implementation vtable.
+ * \param salt HKDF-Extract salt.
+ * \param salt_len HKDF-Extract salt length (in bytes).
+ */
+void br_hkdf_init(br_hkdf_context *hc, const br_hash_class *digest_vtable,
+ const void *salt, size_t salt_len);
+
+/**
+ * \brief The special "absent salt" value for HKDF.
+ */
+#define BR_HKDF_NO_SALT (&br_hkdf_no_salt)
+
+#ifndef BR_DOXYGEN_IGNORE
+extern const unsigned char br_hkdf_no_salt;
+#endif
+
+/**
+ * \brief HKDF input injection (HKDF-Extract).
+ *
+ * This function injects some more input bytes ("key material") into
+ * HKDF. This function may be called several times, after `br_hkdf_init()`
+ * but before `br_hkdf_flip()`.
+ *
+ * \param hc HKDF context.
+ * \param ikm extra input bytes.
+ * \param ikm_len number of extra input bytes.
+ */
+void br_hkdf_inject(br_hkdf_context *hc, const void *ikm, size_t ikm_len);
+
+/**
+ * \brief HKDF switch to the HKDF-Expand phase.
+ *
+ * This call terminates the HKDF-Extract process (input injection), and
+ * starts the HKDF-Expand process (output production).
+ *
+ * \param hc HKDF context.
+ */
+void br_hkdf_flip(br_hkdf_context *hc);
+
+/**
+ * \brief HKDF output production (HKDF-Expand).
+ *
+ * Produce more output bytes from the current state. This function may be
+ * called several times, but only after `br_hkdf_flip()`.
+ *
+ * Returned value is the number of actually produced bytes. The total
+ * output length is limited to 255 times the output length of the
+ * underlying hash function.
+ *
+ * \param hc HKDF context.
+ * \param info application specific information string.
+ * \param info_len application specific information string length (in bytes).
+ * \param out destination buffer for the HKDF output.
+ * \param out_len the length of the requested output (in bytes).
+ * \return the produced output length (in bytes).
+ */
+size_t br_hkdf_produce(br_hkdf_context *hc,
+ const void *info, size_t info_len, void *out, size_t out_len);
+
+/**
+ * \brief SHAKE context.
+ *
+ * The HKDF context is initialized with a "security level". The internal
+ * notion is called "capacity"; the capacity is twice the security level
+ * (for instance, SHAKE128 has capacity 256).
+ *
+ * The caller is responsible for allocating the context where
+ * appropriate. Context initialisation and usage incurs no dynamic
+ * allocation, so there is no release function.
+ */
+typedef struct {
+#ifndef BR_DOXYGEN_IGNORE
+ unsigned char dbuf[200];
+ size_t dptr;
+ size_t rate;
+ uint64_t A[25];
+#endif
+} br_shake_context;
+
+/**
+ * \brief SHAKE context initialization.
+ *
+ * The context is initialized for the provided "security level".
+ * Internally, this sets the "capacity" to twice the security level;
+ * thus, for SHAKE128, the `security_level` parameter should be 128,
+ * which corresponds to a 256-bit capacity.
+ *
+ * Allowed security levels are all multiples of 32, from 32 to 768,
+ * inclusive. Larger security levels imply lower performance; levels
+ * beyond 256 bits don't make much sense. Standard levels are 128
+ * and 256 bits (for SHAKE128 and SHAKE256, respectively).
+ *
+ * \param sc SHAKE context to initialise.
+ * \param security_level security level (in bits).
+ */
+void br_shake_init(br_shake_context *sc, int security_level);
+
+/**
+ * \brief SHAKE input injection.
+ *
+ * This function injects some more input bytes ("key material") into
+ * SHAKE. This function may be called several times, after `br_shake_init()`
+ * but before `br_shake_flip()`.
+ *
+ * \param sc SHAKE context.
+ * \param data extra input bytes.
+ * \param len number of extra input bytes.
+ */
+void br_shake_inject(br_shake_context *sc, const void *data, size_t len);
+
+/**
+ * \brief SHAKE switch to production phase.
<