559 Enigma - 52-bit Key Length

559 : Enigma - 52-bit Key Length

Design render
  • Author: Virantha Ekanayake
  • Description: Silicon implementation of an Enigma I machine with a limited plugboard supporting 3 wires
  • GitHub repository
  • Open in 3D viewer
  • Clock: 0 Hz

How it works

Background

This project features a silicon implementation of a 52-bit equivalent key model of the WWII-era Enigma code machine used by the Germans. The British, led by Alan Turing (as depicted in The Imitation Game), cracked this code, giving the Allies a crucial advantage in the war.

This electronic version is accurate and will match any simulator you can find on the web^1. Although almost every Enigma operates on similar principles, the particular model implemented here is the Enigma I^3 used by the German Army and Air Force; it comes with 3 rotor slots, the 5 original Rotors, the UKW-B Reflector, and plugboard. The only limitation is that the plugboard only supports 3 wires, whereas the actual wartime procedure was to use up to 10 wires. This limits the key length of this implementation to 52-bits. The calculation is shown below.

Key-length Calculation

The Enigma is a symmetric^4 encryption engine, and the equivalent key length is comprised of the different settings and ways the rotors and plugboard can be arranged. See the excellent analysis^5 from Dr. Ray Miller at NSA for more details on the calculations below:

  1. Selecting the three rotors, which can be arranged from right to left in any order:

    5 x 4 x 3 = 60 possible ways

  2. Starting position of each rotor:

    26 * 26 * 26 = 17576

  3. Ring of each rotor (only two right rotors matter):

    26*26 = 676

  4. Plugboard with 3 wires (see table on p.9 for p=3^3):

    = 26! / (26-6)! / 3! / 8 = 3,453,450 ways to plug in 3 wires

The total ways (# of keys) to set up this particular Enigma is therefore:

60 * 17576 * 676 * 3,453,450 =  2,461,904,276,832,000 ways

yielding a key length of ~52-bits.

Implementation

Using the Python-based hardware description tool Amaranth HDL^7 for the first time made building, testing, and generating the Verilog implementation much easier. Given the complexity of the rotors’ input-output mappings, I would’ve needed to write Python scripts anyway to generate Verilog logic. Amaranth streamlined this process and allowed seamless integration with my reference Python implementation for test generation.

  • Rotor design:
    • Meeting the tight area requirements involved several design iterations that narrowly missed targets late in the cycle. Amaranth’s flexibility made re-architecting much simpler. For example, my initial approach of implementing three separate combinational hardware rotors was too large and lacked configurability. I ultimately created a single reconfigurable rotor block that processes data over six cycles, effectively forming a six-rotor pipeline (three forward, three backward after reflection).
  • Plugboard Design:
    • Initial Attempt: A 26-entry, 5-bit lookup table using DFFs, which proved too large.

    • Next Approach: A scan-chain-based design, but the hold-fix buffers and comparison logic made it even larger.

    • Final Solution: A 26-entry, 5-bit lookup table using Skywater 130 standard-cell latches. This worked well since the plugboard functions like a ROM, with only a few initial writes to set the configuration. These writes are precisely pulsed using the state machine.

Key statistics
Utilization 81%
Cells 1583
DFF 67
Latches 130
Frequency 35MHz

Operation

The Enigma is designed to accept an 8-bit input (command plus data) at the clk edge. The internal state machine then takes a varying number of clk cycles to respond, raising the "Ready" signal when it's ready to accept the next command. If the command generates an output, the raw value will be output on the bidir pins, and the LCD display will show the character generated.

Pinouts
Description Width Direction Signal(s)
Command 3 in ui_in[7:5]
Data 5 in ui_in[4:0]
Scrambled output char 5 out uio_out[4:0]
Ready 1 out uio_out[5]
7-segment LCD 7 out uo_out[6:0]
Commands

The machine accepts the following 8 commands:

Encoding[^6] Command Data Description
000 NOP N/A Do nothing
001 LOAD_START Setting 0-25 (A-Z) Set the start position of a rotor. Do this three times in succession to set each of the three rotors (right to left)
010 LOAD_RING Setting 0-25 (A-Z) Set the ring setting of a rotor. Do this three times in succession to set each of the three rotors (right to left)
011 RESET N/A Go back to the initial state
100 SCRAMBLE Input char 0-25 (A-Z) Run a letter through the rotor. The Ready signal will be asserted when the scrambled character is output
101 LOAD_PLUG_ADDR Src 0-25 (A-Z) Set an internal register to where the start of the plug should go. This command should be followed by LOAD_PLUG_DATA to set the destination
110 LOAD_PLUG_DATA Dst 0-25 (A-Z) Set the other end of the plug. Note that this connection is unidirectional, so if you want A,B connected, then you need to do two sequences of these commands to first set A->B and then B->A
111 SET_ROTORS Rotor 0-4 Pick the Rotor type for each slot where Rotor I=0, Rotor II=1, ... Rotor V=4. Do this three times in succession to pick each of the rotors (right to left). Default is Rotor I, II, III from right to left, where Rotor I is closest to the plugboard
Sample run

At some point, I'll have some code ready for running on the RPi on the PC, but for now, here is the pseudo code for setting up and scrambling/descrambling with this machine:

    # Install the rotors
    send_command(SET_ROTORS, 0)   # Set slot 0 to Rotor I
    send_command(SET_ROTORS, 1)   # Set slot 0 to Rotor II
    send_command(SET_ROTORS, 2)   # Set slot 0 to Rotor III

    # Dial start position of the rotors
    send_command(LOAD_START, 15)  # Set rotor 0 start position to P
    send_command(LOAD_START, 5)   # Set rotor 1 start position to F
    send_command(LOAD_START, 1)   # Set rotor 2 start position to B

    # Dial ring position of the rotors
    send_command(LOAD_RING, 18)  # Set rotor 0 start position to S
    send_command(LOAD_RING, 5)   # Set rotor 1 start position to F
    send_command(LOAD_RING, 24)  # Set rotor 2 start position to Y

    # Set up the plugboard
    # First, configure the plugboard default configuration with 
    # no swizzling of letters
    for i in range(26):
        send_command(LOAD_PLUG_ADDR, i)
        send_command(LOAD_PLUG_DATA, i)

    # Now, plug in three wires
    send_command(LOAD_PLUG_ADDR, 0)    # connect A -> N
    send_command(LOAD_PLUG_DATA, 13)

    send_command(LOAD_PLUG_ADDR, 13)   # connect N -> A
    send_command(LOAD_PLUG_DATA, 0)

    send_command(LOAD_PLUG_ADDR, 3)    # connect D -> E
    send_command(LOAD_PLUG_DATA, 4)

    send_command(LOAD_PLUG_ADDR, 4)   # connect E -> D
    send_command(LOAD_PLUG_DATA, 3)

    send_command(LOAD_PLUG_ADDR, 25)    # connect Z -> B
    send_command(LOAD_PLUG_DATA, 1)

    send_command(LOAD_PLUG_ADDR, 1)   # connect D -> Z
    send_command(LOAD_PLUG_DATA, 25)

    # Now, enter letters into the machine and watch the coded char
    # appear on the display
    send_command(SCRAMBLE, 11)  # 'L' -> 'X'
    send_command(SCRAMBLE, 14)  # 'O' -> 'K'
    .
    .
    .

[^6]: See the src/defines.py file

Control FSM

alt text

The state machine diagram source can be found on github^8.

How to test

Design verification

  1. Generate the verilog from the Amarangth HDL source

     cd tt10-enigma
     python -m src.top
    

    This will write a file src/am_top.v with the Enigma block. This block is connected to the TinyTapeout harness using src/project.v

  2. Run the functional test

     cd test
     make
    
  3. Run the gate-level tests: After hardening (synthesis/pnr/gds), copy the gate_level_netlist.v into the test/ directory. Then:

     make -B GATES=yes
    

External hardware

None. Uses the built-in 7-segment display on the PCB.

IO

#InputOutputBidirectional
0din[0]seg[0]dout[0]
1din[1]seg[1]dout[1]
2din[2]seg[2]dout[3]
3din[3]seg[3]dout[4]
4din[4]seg[4]dout[5]
5cmd[0]seg[5]ready
6cmd[1]seg[6]
7cmd[2]GND

Chip location

Controller Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Analog Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Analog Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux tt_um_chip_rom (Chip ROM) tt_um_factory_test (Tiny Tapeout Factory Test) tt_um_oscillating_bones (Oscillating Bones) tt_um_urish_charge_pump (Dickson Charge Pump) tt_um_sonos_flash_party (SONOS Flash Party) tt_um_4Bit_SAR_ADC (4-Bit Successive Approximation ADC) tt_um_cw_vref (Current-Mode Bandgap Reference) tt_um_tt08_aicd_playground (AICD Playground) tt_um_tnt_diff_rx (TT08 Differential Receiver test) tt_um_rejunity_vga_logo (VGA Tiny Logo (1 tile)) tt_um_tommythorn_maxbw (Asynchronous Multiplier) tt_um_rebeccargb_universal_decoder (Universal Binary to Segment Decoder) tt_um_mattvenn_rgb_mixer (RGB Mixer demo5) tt_um_rebeccargb_hardware_utf8 (Hardware UTF Encoder/Decoder) tt_um_find_the_damn_issue (Find The Damn Issue) tt_um_brandonramos_VGA_Pong_with_NES_Controllers (VGA Pong with NES Controllers) tt_um_kb2ghz_xalu (4-bit minicomputer ALU) tt_um_rebeccargb_intercal_alu (INTERCAL ALU) tt_um_a1k0n_demo (Demo by a1k0n) tt_um_rburt16_bias_generator (Bias Generator) tt_um_zec_square1 ("SQUARE-1": VGA/audio demo) tt_um_jmack2201 (Sprite Bouncer with Looping Background Options) tt_um_ran_DanielZhu (Dice) tt_um_gfg_development_tinymandelbrot (TinyMandelbrot) tt_um_LnL_SoC (Lab and Lectures SoC) tt_um_htfab_pi_snake (Pi Snake) tt_um_quarren42_demoscene_top (asic design is my passion) tt_um_crispy_vga (Crispy VGA) tt_um_MichaelBell_canon (TT08 Pachelbel's Canon demo) tt_um_shuangyu_top (Calculator) tt_um_wokwi_407306064811090945 (DDR throughput and flop aperature test) tt_um_08_sws (Sine Wave Synthesizer) tt_um_favoritohjs_scroller (VGA Scroller) tt_um_tt08_wirecube (Wirecube) tt_um_vga_glyph_mode (Glyph Mode) tt_um_a1k0n_vgadonut (VGA donut) tt_um_roy1707018 (RO) tt_um_analog_factory_test (TT08 Analog Factory Test) tt_um_sign_addsub (CMOS design of 4-bit Signed Adder Subtractor) tt_um_patater_demokit (Patater Demo Kit Waggling Rainbow on a Chip) tt_um_algofoogle_tt08_vga_fun (TT08 VGA FUN!) tt_um_simon_cipher (simon_cipher) tt_um_thexeno_rgbw_controller (RGBW Color Processor) tt_um_demosiine_sda (DemoSiine) tt_um_bytex64_munch (Munch) tt_um_alexjaeger_ringoscillator (5MHz Ring Oscillator) tt_um_cfib_demo (cfib Demoscene Entry) tt_um_wokwi_407852791999030273 (Simple 8 Bit ALU) tt_um_Richard28277 (4-bit ALU) tt_um_betz_morse_keyer (Morse Code Keyer) tt_um_nvious_graphics (nVious Graphics) tt_um_tiny_pll (Tiny PLL) tt_um_ezchips_calc (8-Bit Calculator) tt_um_hack_cpu (HACK CPU) tt_um_noritsuna_Vctrl_LC_oscillator (Voltage Controlled LC-Oscillator) tt_um_ring_divider (Divided Ring Oscillator) tt_um_morningjava_r2r_from_matt (Bucket Brigade) tt_um_ephrenm_tsal (TSAL_TT) tt_um_kapilan_alarm (Alarm Clock) tt_um_stochastic_addmultiply_CL123abc (Stochastic Multiplier, Adder and Self-Multiplier) tt_um_wokwi_407760296956596225 (tt08-octal-alu) tt_um_dlfloatmac (DL float MAC) tt_um_wakki_0123_Raw_Transistors (Raw_Transistors) tt_um_faramire_rotary_ring_wrapper (Rotary Encoder WS2812B Control) tt_um_devstdin_LDO_OSC (LDO BG IREF OSC) tt_um_frequency_counter (Frequency Counter SSD1306 OLED) tt_um_rom_test (TT08 SKY130 ROM 'YOLO' Test) tt_um_i2c_peripheral_stevej (i2c peripherals: leading zero count and fnv-1a hash) tt_um_yuri_panchul_schoolriscv_cpu_with_fibonacci_program (schoolRISCV CPU with Fibonacci program) tt_um_yuri_panchul_adder_with_flow_control (Adder with Flow Control) tt_um_brailliance (Brailliance) tt_um_nyan (nyan) tt_um_MichaelBell_mandelbrot (VGA Mandelbrot) tt_um_ssp_opamp (2-stage Opamp Designs) tt_um_fountaincoder_top_ad (pulse_add) tt_um_edwintorok (Rounding error) tt_um_mac (MAC) tt_um_dpmu (DPMU) tt_um_JAC_EE_segdecode (7 Segment Decode) tt_um_wokwi_408118380088342529 (Traffic-light-sequence) tt_um_shiftreg_test (TT08 SKY130 Shift Register 'YOLO' Test) tt_um_yuri_panchul_sea_battle_vga_game (Sea Battle) tt_um_benpayne_ps2_decoder (PS2 Decoder) tt_um_meriac_play_tune (Super Mario Tune on A Piezo Speaker) tt_um_comm_ic_bhavuk (Comm_IC) tt_um_daosvik_aesinvsbox (AES Inverse S-box) tt_um_wokwi_408216451206371329 (Logic Test) tt_um_micro_tiles_container (Micro tile container) tt_um_cattuto_sr_latch (TT08 - experiments with latch-based shift registers) tt_um_rejunity_vga_test01 (VGA Drop (audio/visual demo)) tt_um_silice (Warp) tt_um_wokwi_408231820749720577 (Abacus Lock) tt_um_jayjaywong12 (mulmul) tt_um_emmyxu_obstacle_detection (Obstacle Detection) tt_um_neural_navigators (Neural Net ASIC) tt_um_a1k0n_nyancat (VGA Nyan Cat) tt_um_rebeccargb_styler (Styler) tt_um_resfuzzy (resfuzzy) tt_um_cejmu (CEJMU Beers and Adders) tt_um_16_mic_beamformer_arghunter (16 Mic Beamformer) tt_um_pdm_pitch_filter_arghunter (PDM Pitch Filter) tt_um_pdm_correlator_arghunter (PDM Correlator) tt_um_ddc_arghunter (DDC) tt_um_i2s_to_pwm_arghunter (I2S to PWM ) tt_um_georgboecherer_vco (Analog Voltage Controlled Oscillator) tt_um_supermic_arghunter (Supermic ) tt_um_dmtd_arghunter (DMTD ) tt_um_htfab_bouncy_capsule (Bouncy Capsule) tt_um_samuelm_pwm_generator (PWM generator) tt_um_mattvenn_analog_ring_osc (Ring Oscillators) tt_um_toivoh_demo_deluxe (Sequential Shadows Deluxe [TT08 demo competition]) tt_um_faramire_stopwatch (Simple Stopwatch) tt_um_micro_tiles_container_group2 (Micro tile container (group 2)) tt_um_johshoff_metaballs (Metaballs) tt_um_top (Flame demo) tt_um_NicklausThompson_SkyKing (SkyKing Demo) tt_um_Electom_cla_4bits (4-bit CLA) tt_um_vga_cbtest (Generate VGA output for Color Blindness Test) tt_um_zoom_zoom (Zoom Zoom) tt_um_dpmunit (DPM_Unit) tt_um_clock_divider_arghunter (Clock Divider ) tt_um_dlmiles_poc_fskmodem_hdlctrx (FSK Modem +HDLC +UART (PoC)) tt_um_emilian_muxpga (TinyFPGA resubmit for TT08) tt_um_pyamnihc_dummy_counter (Dummy Counter) tt_um_whynot (Why not?) tt_um_sudana_ota5t_1 (5-T OTA) tt_um_dlmiles_tt08_poc_uart (UART) tt_um_dendraws_donut (donut) tt_um_wokwi_408237988946759681 (Counter) tt_um_tmkong_rgb_mixer (RGB Mixer) tt_um_bgr_agolmanesh (Bandgap Reference) tt_um_z2a_rgb_mixer (RGB Mixer demo) tt_um_vga_clock (VGA clock) tt_um_synth_simple_mm (synth_simple) tt_um_gus16 (GUS16 CPU) tt_um_rejunity_ternary_dot (Ternary 128-element Dot Product) tt_um_virantha_enigma (Enigma - 52-bit Key Length) tt_um_atomNPU (AtomNPU) tt_um_alphaonesoc (AlphaOneSoC) tt_um_gxrii_spi_sevenseg (SPI 7-segment display) tt_um_urish_simon (Simon Says memory game) tt_um_branch_pred (TinyTapeout Minimal Branch Predictor) tt_um_xor_encryption (Xor-Logic) tt_um_MAC_Accelerator_OnSachinSharma (MAC Operation) tt_um_moody_mimosa (Moody-mimosa) tt_um_wrapper (6Digit7SegClock) tt_um_MichaelBell_tinyQV (TinyQV Risc-V SoC) tt_um_devmonk_ay8913 (Classic 8-bit era Programmable Sound Generator AY-3-8913) tt_um_toivoh_demo (Orion Iron Ion [TT08 demo competition]) tt_um_mattvenn_r2r_dac_3v3 (Analog 8 bit 3.3v R2R DAC) tt_um_2048_vga_game (2048 sliding tile puzzle game (VGA)) tt_um_test_commit (Microrobotics-Basic-IPs) tt_um_jimktrains_vslc (VSLC - Very Small Logic Controller with a timer and servo control) tt_um_gamepad_pmod_demo (Gamepad Pmod Demo) tt_um_mattvenn_adjustable_psu_counter (Adjustable supply digital counter) tt_um_tinytapeout_logo_screensaver (VGA Screensaver with Tiny Tapeout Logo) tt_um_mattvenn_spi_test (SPI test) tt_um_huffman_coder (Huffmann_Coder) tt_um_multiplier (Vedic multiplier) tt_um_wokwi_422964384478997505 (NAND) tt_um_wokwi_422964754310747137 (DaliaProjekt) tt_um_wokwi_422957918936350721 (TinyTapeout 4 bit ripple carry adder) tt_um_wokwi_422961309631153153 (Tinytapeout_design_ANP) tt_um_wokwi_422957954050029569 (Extremely cool stuff (secret)) tt_um_wokwi_422964381148718081 (test/15/02/25) tt_um_wokwi_422959954857061377 (example1) tt_um_wokwi_422960174616660993 (First design) tt_um_schoeberl_wildcat (Wildcat RISC-V) tt_um_wokwi_422962760920307713 (4 Bit Adder with Overflow Counter) tt_um_kentrane_tinyspectrum (Tiny piano) tt_um_wokwi_422962914561876993 (Emil Njor's Design) tt_um_i2c_regf (Asynchronous I2C Registerfile Interface) tt_um_wokwi_422960054456096769 (3-bit register print) tt_um_wokwi_422960130190575617 (Four basic building blocks) tt_um_wokwi_422965035809389569 (3 Bit Adder) tt_um_wokwi_422958894385882113 (TinyChipDesign) tt_um_tappu_tobias1012 (Tappu) tt_um_wokwi_422960332734617601 (Enter-Code) tt_um_wokwi_422960080008854529 (Special code for letter n) tt_um_wokwi_422957657550394369 (Full Adder) tt_um_mp_lif_schor (mp_LIF_neuron) tt_um_wokwi_422962959838345217 (Holm's TinyTapeOut 4-bit adder) tt_um_asgerwenneb (Custom SRAM) tt_um_wokwi_422960491546730497 (ANDNOT) tt_um_Strider93 (digital LIF Neuron) tt_um_wokwi_422960078645704705 (Hero on Tape) tt_um_wokwi_422959974126748673 (my_own_chip) tt_um_wokwi_422968416190311425 (Encoder) tt_um_wokwi_422962904571040769 (simplePass) tt_um_keszocze_ssmcl (SSMCl) tt_um_luke_clock (TT10_Luke_Clock) tt_um_enjens (Verilog based clock to 7-segment counter) tt_um_wokwi_422968696249282561 (Simple NAND 2) tt_um_wokwi_422960085743520769 (Adder) tt_um_UartMain (XOR Cipher) tt_um_torurstrom_async_lock (Asynchronous Locking Unit) tt_um_larva (LaRVa CPU) tt_um_zhouzhouthezhou_adder (tt10_zhouzhouthezhou_adder) tt_um_bg_DanielZhu123 (Bandgap) tt_um_jp_cd101_saw (KCH CD101 Saw Synth) tt_um_hpdl1414_uart_atudoroi (TT10 HPDL 1414 Uart) tt_um_jun1okamura_test0 (7-segment with LFSR) tt_um_strau0106_simple_viii (simple-viii) tt_um_obriensp_jtag (JTAG TAP) tt_um_10_vga_crossyroad (Crossyroad) tt_um_bilal_trng (TRNG) tt_um_space_invaders_game (Space Invaders ASIC) tt_um_sushi_demo (zc-sushi-demo) tt_um_kch_cd101 (kch cd101) tt_um_uart_bgdtanasa (ttUART) tt_um_zedulo_spitest1 (SimpleSPIdev) tt_um_daobaanh_rng (RNG_test) tt_um_mattvenn_level_shifter (Level Shifter) tt_um_gcd_stephan (15bit GCD) tt_um_alexandercoabad_mixedsignal (Mixed-Signal) tt_um_spacewar (XY Spacewar) tt_um_gregac_tiny_nn (Tiny Neural Network Accelerator) tt_um_log_afpm (16-bit Logarithmic Approximate Floating Point Multiplier) tt_um_rkarl_Spiral (TT_spiralPattern) tt_um_led_jellyant (ledtest) tt_um_project (Simple shift Reg) tt_um_DaDDS (DaDDS) tt_um_nithishreddykvs (Pulse Width Modulation) tt_um_monishvr_fifo (Synchronous FIFO) tt_um_reemashivva_fifo (Asynchronous FIFO) tt_um_save_buffer_hash_table (Tiny Hash Table) tt_um_drum_goekce (DRUM) tt_um_rte_sine_synth (Sine Synth) tt_um_simon2024_c_element_top (Muller C-element) tt_um_tiny_shader_mole99 (Tiny Shader) tt_um_flummer_ltc (Linear Timecode (LTC) generator) tt_um_bitty (Bitty) tt_um_ole_moller_priority_encoder_to_7_segment_decoder (Priority-encoder) tt_um_algofoogle_vga (IHP VGA demo) tt_um_ultra_tiny_cpu (UltraTiny-CPU) tt_um_uwasic_dinogame (UW ASIC - Optimized Dino) tt_um_Qwendu_spi_fpu (SPI FPU) tt_um_rte_eink_driver (E-ink display driver) tt_um_urish_sic1 (SIC-1 8-bit SUBLEQ Single Instruction Computer) tt_um_kianV_rv32ima_uLinux_SoC (KianV uLinux SoC) tt_um_autosel (I2C EEPROM Project Selection) tt_um_tnt_rom_test (TT09 SKY130 ROM Test) tt_um_tnt_rom_nolvt_test (TT09 SKY130 ROM Test (no LVT variant)) tt_um_tt_tinyQV (TinyQV SoC with additional peripherals) tt_um_htfab_dg_dac (Dempsey-Gorman DAC) tt_um_algofoogle_raybox_zero (raybox-zero TTCAD25a edition) tt_um_htfab_checkers (Overengineered Checkers) tt_um_sky130_as_sc_hs (sky130_as_sc_hs test) tt_um_sky130_as_sc_hs_dyn_test (sky130_as_sc_hs dyn test) tt_um_rejunity_z80 (Zilog Z80) tt_um_tnt_rf_yolo_test (TTCAD25a SKY130 RF YOLO Test) tt_um_2x2MatrixMult_Vort3xed (UART Matrix Multiplier) tt_um_zerotoasic_logo_screensaver (VGA Screensaver with Zero to ASIC Logo) tt_um_rejunity_lgn_mnist (LGN hand-written digit classifier (MNIST, 16x16 pixels)) tt_um_wokwi_422192563267712001 (Padlock) tt_um_rc_oscillators (R-C Oscillators) tt_um_tnt_ff_yolo_test (TTCAD25a SKY130 FF YOLO Test) Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available Available