HaLo
Non-Interactive Mode

Non-Interactive Mode

When no command is written to a chip, it will automatically generate a random challenge and sign it using key slot #2 while incrementing a counter. For chips with this feature you cannot request signatures of external data from key slot #2.

⚠️

Experimental feature available in version c3 or greater. Interface is expected to change.

Verification Example

Using the URL below, we can verify the randomly generated challenge against the secondary public key of the HaLo:

https://eth.vrfy.ch/?v=c3&static=41046ACA3F246833017F8932A42518BBC0602E7B41FC4A03F02417B73685FF01AEAB8D653466D6FA2450A085C29BA31169F83A489DE46BC4CB0BB4F567DF7A66BE8E4104BDC6288D344F129820317411D8A8283942DCDB4B2D2F86E78F22F944160B6038C9E8DC747710349C2E55E6BC52D8745B749B39051BF72A0307B339257A48AECF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000&latch1=0000000000000000000000000000000000000000000000000000000000000000&latch2=0000000000000000000000000000000000000000000000000000000000000000&cmd=810200000009DC18D3F30E06E9A3C10D41EDDA09404654C502F70E67E80D781876D800&res=3045022100FCAAEFFCAB25E4B78BABB68C733DD2827FDC76E927F87C50A392E257583797DD02201A9CA7012FF3CC1C3380E1832BC733C69D743445A8DA4F664095F134927DA9170000000000&

  1. Scan the HaLo chip and parse the NDEF record. The static parameter contains the public key for key slot #2 or pkey2.

static

41 04BDC6288D344F129820317411D8A8283942DCDB4B2D2F86E78F22F944160B6038C9E8DC747710349C2E55E6BC52D8745B749B39051BF72A0307B339257A48AECF
  1. When there was no command initiated, the cmd parameter includes a command code and challenge:
  • command code: 2 bytes (always: 8102).
  • challenge: 32 bytes (e.g. 00000009DC18…), which consists of:
    • Big-endian UInt32: incremental counter, increases by 1 on each tap.
    • Random 28 bytes: random number generated by the chip on each tap.
    • Zero-padding: 1 byte (always: 00).

cmd

8102 00000002F202C592C809428C2C763C3AB3A4BBF5475DD4567A45F8200E82C63D 00
  1. Parse the res parameter includes the ECDSA signature:

res

30450221009FB0D4E3F7BF343219E4A8779059412E3E1A2F26EAAE69B6246EA1AD118D3EE40220783DEBF12DF1D60DF6488543C8100937E9A596028B2D97D65279378713157CF1 0000000000
  1. Verify the ECDSA signature against the publick key and challenge:
const EC = require('elliptic').ec;
const ec = new EC('secp256k1');
 
let pkey2 = "04BDC6288D344F129820317411D8A8283942DCDB4B2D2F86E78F22F944160B6038C9E8DC747710349C2E55E6BC52D8745B749B39051BF72A0307B339257A48AECF";
let challenge = "00000002F202C592C809428C2C763C3AB3A4BBF5475DD4567A45F8200E82C63D";
let signature = "30450221009FB0D4E3F7BF343219E4A8779059412E3E1A2F26EAAE69B6246EA1AD118D3EE40220783DEBF12DF1D60DF6488543C8100937E9A596028B2D97D65279378713157CF1";
 
let key = ec.keyFromPublic(pkey2.toString('hex'), 'hex');
if (!key.verify(challenge, signature)) {
    return {"error": "Unable to verify HaLo signature."};
}

Note that unlike typical Ethereum messages, the random number is not keccak256 hashed prior to being signed.