## poly1305.bdscr ## Ref: "ChaCha20 and Poly1305 for IETF protocols" ## Nir & Langley, January 19, 2015 ## <http://tools.ietf.org/html/draft-irtf-cfrg-chacha20-poly1305-08> ## Section 2.5.2. Poly1305 Example and Test Vector # Set the constant prime "P" to be 2^130-5: P = (1<<130) - 5 # 1361129467683753853853498429727072845819 printf("Prime, P: %x\n", P) # 0x3fffffffffffffffffffffffffffffffb # set a 128-bit mask of 1's - we'll use this below mask128 = ((1<<128)-1) # 256-bit key in network order k = 0x85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b printf("Key in network order:\n [%064x]\n", k) # split into (r,s) # s is the right-hand 128 bits s = k band mask128 printf("s in network order : [%032x]\n", s) # Set s as 128-bit little-endian number s = revbytes(s, 128/8) printf("s as 128-bit number: 0x%x\n", s) puts( "(Correct s : 0x1bf54941aff6bf4afdb20dfb8a800301)") # r is the left-hand 128 bits r = (k >> 128) band mask128 printf("r in network order : [%032x]\n", r) # Set r as 128-bit little-endian number r = revbytes(r, 128/8) printf("r as 128-bit number: 0x%x\n", r) # clamp r r = r band 0x0ffffffc0ffffffc0ffffffc0fffffff printf("r after clamping : 0x%x\n", r) puts( "(Correct r : 0x806d5400e52447c036d555408bed685)") # Message to be Authenticated in network order msg = 0x43727970746f6772617068696320466f72756d2052657365617263682047726f7570 mbytes = bytelen(msg) # Careful if have leading zero bytes nblocks = (mbytes + 15) / 16 printf("Message in network order:\n [%x]\n", msg) println("msg length in bytes = ", mbytes, " => ", nblocks, " blocks") # Reverse order of message bytes then take in blocks of 128 bits msg = revbytes(msg, bytelen(msg)) !msg # set a variable "accumulator" to zero acc = 0 # Loop through each block of 16 bytes (128 bits) for i in (1..nblocks) do printf("Acc = %x\n", acc); block = msg & mask128; printf("Block = %x\n", block); block = (0x01 << (bytelen(block))*8) | block; printf("Block with 0x01 byte = %x\n", block); # debug values printf("Acc + block = = %x\n", acc + block); printf("(Acc + Block) * r =\n\t%x\n", (acc + block) * r); # do calc in one line acc = ((acc+block)*r) mod P; printf("((Acc + Block) * r) %% P = %x\n", acc); # Shift message block by 16 bytes msg = msg >> 128; done tag = acc + s # 905406785994486245610219399192143267496 # Tag as a little-endian number: printf("Acc + s = %x\n", tag) # 0x2a927010caf8b2bc2c6365130c11d06a8 # Reverse order of bytes tag = revbytes(tag, 16); printf("Serialize to get the tag as a 16-byte octet string:\nComputed: [%032x]\n", tag) # Correct value puts "Correct: [a8061dc1305136c6c22b8baf0c0127a9]" # Check our result with correct answer printf("Result is %q\n", (tag == 0xa8061dc1305136c6c22b8baf0c0127a9));