init: v1.0.0

This commit is contained in:
yaole
2026-05-27 23:03:00 +08:00
commit 8d97f750eb
466 changed files with 80067 additions and 0 deletions
+1044
View File
File diff suppressed because it is too large Load Diff
+26
View File
@@ -0,0 +1,26 @@
package sm3
import (
"golang.org/x/sys/cpu"
)
var useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI2
//go:noescape
func blockAsmAVX2(dig *digest, p []byte)
var block func(dig *digest, p []byte)
func init() {
if useAVX2 {
block = blockAsmAVX2
} else {
block = blockGeneric
}
}
// BlockAsmAVX2 export blockAsmAVX2 for test
var BlockAsmAVX2 = blockAsmAVX2
// BlockGeneric export blockGeneric for test
var BlockGeneric = blockGeneric
+598
View File
@@ -0,0 +1,598 @@
#include "textflag.h"
// SM3 block routine.
//
// No "function stitching" now.
//
// The algorithm is detailed in GB/T 32905-2016
// FFt(x,y,z) = GGt(x,y,z) = Parity(x,y,z) for 0 <= t <= 15
// FFt(x,y,z) = Maj(x,y,z) for 15 <= t <= 63
// GGt(x,y,z) = Ch(x,y,z) for 15 <= t <= 63
//
// Wt = Mt; for 0 <= t <= 15
// Wt = P1(Wt-16 xor Wt-9 xor ROTL(Wt-3,15))
// xor ROTL(Wi-13, 7) xor Wt-6 for 16 <= t <= 67
// W't = Wt xor Wt+4 for 0 <= t <= 63.
//
// a = V0
// b = V1
// c = V2
// d = V3
// e = V4
// f = V5
// g = V6
// h = V7
//
// for t = 0 to 63 {
// SS1 = ROTL(ROTL(a,12) + E + ROTL(Tt, t mod 32), 7)
// SS2 = SS1 xor ROTL(a,12)
// TT1 = FFt(a,b,c) + D + SS2 +W't
// TT2 = GGt(e,f,g) + h + SS1 +Wt
// d = c
// c = ROTL(b,9)
// b = a
// a = TT1
// h = g
// g = ROTL(f,19)
// f = e
// e = P0(TT2)
// }
//
// V0 = a xor V0
// V1 = b xor V1
// V2 = c xor V2
// V3 = d xor V3
// V4 = e xor V4
// V5 = f xor V5
// V6 = g xor V6
// V7 = h xor V7
// Definitions for AVX2 version
// xorm (mem), reg
// Xor reg to mem using reg-mem xor and store
#define xorm(P1, P2) \
XORL P2, P1; \
MOVL P1, P2
#define XDWORD0 Y4
#define XDWORD1 Y5
#define XDWORD2 Y6
#define XDWORD3 Y7
#define XWORD0 X4
#define XWORD1 X5
#define XWORD2 X6
#define XWORD3 X7
#define XTMP0 Y0
#define XTMP1 Y1
#define XTMP2 Y2
#define XTMP3 Y3
#define XTMP4 Y8
#define XTMP5 Y11
#define XFER Y9
#define BYTE_FLIP_MASK Y13 // mask to convert LE -> BE
#define X_BYTE_FLIP_MASK X13
#define NUM_BYTES DX
#define INP DI
#define CTX SI // Beginning of digest in memory (a, b, c, ... , h)
#define a AX
#define b BX
#define c CX
#define d R8
#define e DX
#define f R9
#define g R10
#define h R11
#define old_h R11
#define TBL BP
#define SRND SI // SRND is same register as CTX
#define T1 R12
#define y0 R13
#define y1 R14
#define y2 R15
#define y3 DI
// Offsets
#define XFER_SIZE 2*2*68*4
#define INP_END_SIZE 8
#define INP_SIZE 8
#define _XFER 0
#define _INP_END _XFER + XFER_SIZE
#define _INP _INP_END + INP_END_SIZE
#define STACK_SIZE _INP + INP_SIZE
// update XDWORD0
#define SM3_SCHED(XDWORD0, XDWORD1, XDWORD2, XDWORD3)\
; \ // ################################### Message Schedule ###########################
VPALIGNR $8, XDWORD2, XDWORD3, XTMP0; \ // XTMP0 = W[-6]
VPALIGNR $12, XDWORD0, XDWORD1, XTMP1; \ // XTMP1 = W[-13]
VPSLLD $7, XTMP1, XTMP2; \
VPSRLD $(32-7), XTMP1, XTMP1; \
VPXOR XTMP2, XTMP1, XTMP1; \ // XTMP1 = (w[-13] <<< 7)
VPXOR XTMP1, XTMP0, XTMP0; \ // XTMP0 = (w[-13] <<< 7) ^ w[-6]
; \
VPALIGNR $12, XDWORD1, XDWORD2, XTMP1; \ // XTMP1 = W[-9]
VPXOR XDWORD0, XTMP1, XTMP1; \ // XTMP1 = W[-9]^W[-16]
; \
VPSHUFD $0xA5, XDWORD3, XTMP2; \ // XTMP2 = W[-3] {BBAA}
VPSRLQ $17, XTMP2, XTMP4; \ // XTMP4 = W[-3] <<< 15 {xBxA}
VPSHUFB shuff_00BA<>(SB), XTMP4, XTMP4; \ // XTMP4 = W[-3] <<< 15 {00BA}
VPXOR XTMP1, XTMP4, XTMP4; \ // XTMP4 = W[-9]^W[-16] ^ (W[-3] <<< 15) {xxBA}
VPSHUFD $0x50, XTMP4, XTMP4; \ // XTMP4 = W[-9]^W[-16] ^ (W[-3] <<< 15) {BBAA}
VPSRLQ $17, XTMP4,XTMP2; \ // {xBxA}
VPSRLQ $9, XTMP4,XTMP3; \ // {xBxA}
VPXOR XTMP2, XTMP4, XTMP4; \ //
VPXOR XTMP3, XTMP4, XTMP4; \ // XTMP4 = p1 {xBxA}
VPSHUFB shuff_00BA<>(SB), XTMP4, XTMP4; \ // XTMP4 = p1 {00BA}
VPXOR XTMP4, XTMP0, XTMP5; \ // XTMP5 = {..., ..., W[1], W[0]}
; \
VPALIGNR $4, XDWORD3, XTMP5, XTMP2; \ // XTMP2 = {W[0], W[-1], W[-2], W[-3]}
VPSHUFD $0xFA, XTMP2, XTMP2; \ // XTMP2 = {W[0], W[0], W[-1], W[-1]} {DDCC}
VPSRLQ $17, XTMP2, XTMP4; \ // XTMP4 = W[-3] <<< 15 {xDxC}
VPSHUFB shuff_DC00<>(SB), XTMP4, XTMP4; \ // XTMP4 = W[-3] <<< 15 {DC00}
VPXOR XTMP1, XTMP4, XTMP4; \ // XTMP4 = W[-9]^W[-16] ^ (W[-3] <<< 15) {DCxx}
VPSHUFD $0xFA, XTMP4, XTMP4; \ // XTMP4 = W[-9]^W[-16] ^ (W[-3] <<< 15) {DDCC}
VPSRLQ $17, XTMP4,XTMP2; \
VPSRLQ $9, XTMP4,XTMP3; \
VPXOR XTMP2, XTMP4, XTMP4; \
VPXOR XTMP3, XTMP4, XTMP4; \ // XTMP4 = p1 {xDxC}
VPSHUFB shuff_DC00<>(SB), XTMP4, XTMP4; \ // XTMP4 = p1 {DC00}
VPXOR XTMP4, XTMP5,XDWORD0
// 16-0
// SRND = # of {4 round}
// T is saved in (dist_T)(TBL)(SRND*1)
// W is saved in (dist_W)(SP)(SRND*2)
// W' is saved in (dist_W + 68*4*2)(SP)(SRND*1)
#define DO_ROUND16(dist_T, dist_W, a, b, c, d, e, f, g, h) \
; \ // ################################### RND 0 - 15 ###########################
RORXL $(32-12), a, y2; \ // y2 = a <<< 12
MOVL y2, y3; \
ADDL e, y3; \ // y3 = (a <<< 12) + e
ADDL (dist_T)(TBL)(SRND*1), y3; \ // y3 = (a <<< 12) + e + T
RORXL $(32-7), y3, y3; \ // y3 = ss1
ADDL y3, h; \ // h = h+ss1
XORL y2, y3; \ // y3 = ss2
ADDL y3, d; \ // d = d+ss2
; \
ADDL (dist_W)(SP)(SRND*2), h; \ // h = h + ss1 + w
ADDL (dist_W+68*4*2)(SP)(SRND*2), d; \ // d = d + ss2 + w'
; \
MOVL a, y1; \ // y1 = a //FF //PARITY
XORL b, y1; \ // y1 = a^b //FF //PARITY
XORL c, y1; \ // y1 = a^b^c //FF //PARITY
ADDL y1, d; \ // d = TT1
; \
MOVL e, y2; \ // y2 = e // GG //PARITY
XORL f, y2; \ // y2 = e^f // GG //PARITY
XORL g, y2; \ // y2 = e^f^g // GG //PARITY
ADDL y2, h; \ // h = TT2
; \
RORXL $(32-8), h, y0; \ // y0 = TT2<<<8
XORL h,y0; \ // y0 = (TT2<<<8)^TT2
RORXL $(32-9), y0, y0; \ // y0 = ((TT2<<<8)^TT2)<<<9
XORL y0, h; \ // h = p0(TT2)
; \
RORXL $(32-9), b, b; \
RORXL $(32-19), f, f
// 48
#define DO_ROUND48(dist_T, dist_W, a, b, c, d, e, f, g, h) \
; \ // ################################### RND 16 - 63 ###########################
RORXL $(32-12), a, y2; \ // y2 = a <<< 12
MOVL y2, y3; \
ADDL e, y3; \ // y3 = (a <<< 12) + e
ADDL (dist_T)(TBL)(SRND*1), y3; \ // y3 = (a <<< 12) + e + T
RORXL $(32-7), y3, y3; \ // y3 = ss1
ADDL y3, h; \ // h = h+ss1
XORL y2, y3; \ // y3 = ss2
ADDL y3, d; \ // d = d+ss2
; \
ADDL (dist_W)(SP)(SRND*2), h; \ // h = h + ss1 + w
ADDL (dist_W+68*4*2)(SP)(SRND*2), d; \ // d = d + ss2 + w'
; \
MOVL a, y3; \ // y3 = a //FF MAJA
ORL c, y3; \ // y3 = a|c // MAJA
ANDL b, y3; \ // y3 = (a|c)&b // MAJA
MOVL a, T1; \ // T1 = a // MAJB
ANDL c, T1; \ // T1 = a&c // MAJB
ORL T1, y3; \ // y3 = MAJ = ((a|c)&b)|(a&c) // MAJ
ADDL y3, d; \ // d = TT1
; \
MOVL f, y2; \ // y2 = f //GG CH
XORL g, y2; \ // y2 = f^g // CH
ANDL e, y2; \ // y2 = (f^g)&e // CH
XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH
ADDL y2, h; \ // h = TT2
; \
RORXL $(32-8), h, y0; \ // y0 = TT2<<<8
XORL h,y0; \ // y0 = (TT2<<<8)^TT2
RORXL $(32-9), y0, y0; \ // y0 = ((TT2<<<8)^TT2)<<<9
XORL y0, h; \ // h = p0(TT2)
; \
RORXL $(32-9), b, b; \
RORXL $(32-19), f, f
// stack:
// block0 block1
// 0*8: W[0:4] V[0:4]
// 1*8: W[4:8] V[4:8]
// ...
// 67*8: W[64:68] V[64:68]
// 68*8: W'[0:4] V'[0:4]
// 69*8: W'[4:8] V'[4:8]
// ...
// 135*8: W'[64:68] V'[64:68]
// 136*8: _INP_END(SP) - Pointer to the last block
// 137*8: _INP(SP) - Save INP in round computation.
//
// STACK_SIZE = 1088+8+8 = 1104
// func blockAsmAVX2(dig *digest, p []byte)
TEXT ·blockAsmAVX2(SB), 0, $1104-32
MOVQ dig+0(FP), CTX
MOVQ p_base+8(FP), INP
MOVQ p_len+16(FP), NUM_BYTES
LEAQ -64(INP)(NUM_BYTES*1), NUM_BYTES // Pointer to the last block
MOVQ NUM_BYTES, _INP_END(SP) // save to stack
CMPQ NUM_BYTES, INP
JE avx2_only_one_block
// Load initial digest
MOVL 0(CTX), a // a = H0
MOVL 4(CTX), b // b = H1
MOVL 8(CTX), c // c = H2
MOVL 12(CTX), d // d = H3
MOVL 16(CTX), e // e = H4
MOVL 20(CTX), f // f = H5
MOVL 24(CTX), g // g = H6
MOVL 28(CTX), h // h = H7
avx2_loop0: // at each iteration works with one block (512 bit)
// load two blocks64*2 bytes
VMOVDQU (0*32)(INP), XTMP0 // p[0:4]
VMOVDQU (1*32)(INP), XTMP1
VMOVDQU (2*32)(INP), XTMP2
VMOVDQU (3*32)(INP), XTMP3
VMOVDQU flip_mask<>(SB), BYTE_FLIP_MASK
// Apply Byte Flip Mask: LE -> BE
VPSHUFB BYTE_FLIP_MASK, XTMP0, XTMP0
VPSHUFB BYTE_FLIP_MASK, XTMP1, XTMP1
VPSHUFB BYTE_FLIP_MASK, XTMP2, XTMP2
VPSHUFB BYTE_FLIP_MASK, XTMP3, XTMP3
// XTMP0:XTMP1 - first block
// XTMP0: w7, w6, w5, w4, w3, w2, w1,w0
// XTMP1: w15,w14,w13,w12,w11,w10,w9,w8
// XTMP3:XTMP2 - second block
// XTMP2: u7, u6, u5, u4, u3, u2, u1,u0
// XTMP3: u15,u14,u13,u12,u11,u10,u9,u8
// XDWORD0: u3, u2, u1, u0, w3, w2, w1,w0
// XDWORD1: u7, u6, u5, u4, w7, w6, w5, w4
// XDWORD2: u11,u10,u9, u8, w11,w10,w9,w8
// XDWORD3: u15,u14,u13,u12,w15,w14,w13,w12
// Transpose data into high/low parts
VPERM2I128 $0x20, XTMP2, XTMP0, XDWORD0 // w3, w2, w1, w0
VPERM2I128 $0x31, XTMP2, XTMP0, XDWORD1 // w7, w6, w5, w4
VPERM2I128 $0x20, XTMP3, XTMP1, XDWORD2 // w11, w10, w9, w8
VPERM2I128 $0x31, XTMP3, XTMP1, XDWORD3 // w15, w14, w13, w12
MOVQ $T256<>(SB), TBL // Loading address of table with round-specific constants
avx2_last_block_enter:
ADDQ $64, INP
MOVQ INP, _INP(SP)
XORQ SRND, SRND // SRND increace 16 of each 4 rounds (dist of T)
// for w0 - w15
// Do 4 rounds and scheduling
VMOVDQU XDWORD0, (_XFER + 0*32)(SP)(SRND*2)
VPXOR XDWORD0, XDWORD1, XFER
VMOVDQU XFER, (_XFER + 0*32+68*4*2)(SP)(SRND*2)
SM3_SCHED(XDWORD0, XDWORD1, XDWORD2, XDWORD3)
DO_ROUND16(0*4, 0*32+0, a, b, c, d, e, f, g, h)
DO_ROUND16(1*4, 0*32+4, d, a, b, c, h, e, f, g)
DO_ROUND16(2*4, 0*32+8, c, d, a, b, g, h, e, f)
DO_ROUND16(3*4, 0*32+12, b, c, d, a, f, g, h, e)
VMOVDQU XDWORD1, (_XFER + 1*32)(SP)(SRND*2)
VPXOR XDWORD1, XDWORD2, XFER
VMOVDQU XFER, (_XFER + 1*32+68*4*2)(SP)(SRND*2)
SM3_SCHED(XDWORD1, XDWORD2, XDWORD3, XDWORD0)
DO_ROUND16(4*4, 1*32+0, a, b, c, d, e, f, g, h)
DO_ROUND16(5*4, 1*32+4, d, a, b, c, h, e, f, g)
DO_ROUND16(6*4, 1*32+8, c, d, a, b, g, h, e, f)
DO_ROUND16(7*4, 1*32+12, b, c, d, a, f, g, h, e)
VMOVDQU XDWORD2, (_XFER + 2*32)(SP)(SRND*2)
VPXOR XDWORD2, XDWORD3, XFER
VMOVDQU XFER, (_XFER + 2*32+68*4*2)(SP)(SRND*2)
SM3_SCHED(XDWORD2, XDWORD3, XDWORD0, XDWORD1)
DO_ROUND16(8*4, 2*32+0, a, b, c, d, e, f, g, h)
DO_ROUND16(9*4, 2*32+4, d, a, b, c, h, e, f, g)
DO_ROUND16(10*4,2*32+8, c, d, a, b, g, h, e, f)
DO_ROUND16(11*4,2*32+12, b, c, d, a, f, g, h, e)
VMOVDQU XDWORD3, (_XFER + 3*32)(SP)(SRND*2)
VPXOR XDWORD3, XDWORD0, XFER
VMOVDQU XFER, (_XFER + 3*32+68*4*2)(SP)(SRND*2)
SM3_SCHED(XDWORD3, XDWORD0, XDWORD1, XDWORD2)
DO_ROUND16(12*4, 3*32+0, a, b, c, d, e, f, g, h)
DO_ROUND16(13*4, 3*32+4, d, a, b, c, h, e, f, g)
DO_ROUND16(14*4, 3*32+8, c, d, a, b, g, h, e, f)
DO_ROUND16(15*4, 3*32+12, b, c, d, a, f, g, h, e)
ADDQ $4*16, SRND
avx2_loop1:
// for w16 - w47 with scheduling (32 rounds)
VMOVDQU XDWORD0, (_XFER + 0*32)(SP)(SRND*2)
VPXOR XDWORD0, XDWORD1, XFER
VMOVDQU XFER, (_XFER + 0*32+68*4*2)(SP)(SRND*2)
SM3_SCHED(XDWORD0, XDWORD1, XDWORD2, XDWORD3)
DO_ROUND48(0*4, 0*32+0, a, b, c, d, e, f, g, h)
DO_ROUND48(1*4, 0*32+4, d, a, b, c, h, e, f, g)
DO_ROUND48(2*4, 0*32+8, c, d, a, b, g, h, e, f)
DO_ROUND48(3*4, 0*32+12, b, c, d, a, f, g, h, e)
VMOVDQU XDWORD1, (_XFER + 1*32)(SP)(SRND*2)
VPXOR XDWORD1, XDWORD2, XFER
VMOVDQU XFER, (_XFER + 1*32+68*4*2)(SP)(SRND*2)
SM3_SCHED(XDWORD1, XDWORD2, XDWORD3, XDWORD0)
DO_ROUND48(4*4, 1*32+0, a, b, c, d, e, f, g, h)
DO_ROUND48(5*4, 1*32+4, d, a, b, c, h, e, f, g)
DO_ROUND48(6*4, 1*32+8, c, d, a, b, g, h, e, f)
DO_ROUND48(7*4, 1*32+12, b, c, d, a, f, g, h, e)
VMOVDQU XDWORD2, (_XFER + 2*32)(SP)(SRND*2)
VPXOR XDWORD2, XDWORD3, XFER
VMOVDQU XFER, (_XFER + 2*32+68*4*2)(SP)(SRND*2)
SM3_SCHED(XDWORD2, XDWORD3, XDWORD0, XDWORD1)
DO_ROUND48(8*4, 2*32+0, a, b, c, d, e, f, g, h)
DO_ROUND48(9*4, 2*32+4, d, a, b, c, h, e, f, g)
DO_ROUND48(10*4,2*32+8, c, d, a, b, g, h, e, f)
DO_ROUND48(11*4,2*32+12, b, c, d, a, f, g, h, e)
VMOVDQU XDWORD3, (_XFER + 3*32)(SP)(SRND*2)
VPXOR XDWORD3, XDWORD0, XFER
VMOVDQU XFER, (_XFER + 3*32+68*4*2)(SP)(SRND*2)
SM3_SCHED(XDWORD3, XDWORD0, XDWORD1, XDWORD2)
DO_ROUND48(12*4,3*32+0, a, b, c, d, e, f, g, h)
DO_ROUND48(13*4,3*32+4, d, a, b, c, h, e, f, g)
DO_ROUND48(14*4,3*32+8, c, d, a, b, g, h, e, f)
DO_ROUND48(15*4,3*32+12, b, c, d, a, f, g, h, e)
ADDQ $4*16, SRND
CMPQ SRND, $12*16
JB avx2_loop1
// w48 - w63 processed with one scheduling (last 16 rounds)
VMOVDQU XDWORD0, (_XFER + 0*32)(SP)(SRND*2)
VPXOR XDWORD0, XDWORD1, XFER
VMOVDQU XFER, (_XFER + 0*32+68*4*2)(SP)(SRND*2)
SM3_SCHED(XDWORD0, XDWORD1, XDWORD2, XDWORD3) // scheduling XDWORD0 for W64-W67
DO_ROUND48(0*4, 0*32+0, a, b, c, d, e, f, g, h)
DO_ROUND48(1*4, 0*32+4, d, a, b, c, h, e, f, g)
DO_ROUND48(2*4, 0*32+8, c, d, a, b, g, h, e, f)
DO_ROUND48(3*4, 0*32+12, b, c, d, a, f, g, h, e)
VMOVDQU XDWORD1, (_XFER + 1*32)(SP)(SRND*2)
VPXOR XDWORD1, XDWORD2, XFER
VMOVDQU XFER, (_XFER + 1*32+68*4*2)(SP)(SRND*2)
DO_ROUND48(4*4, 1*32+0, a, b, c, d, e, f, g, h)
DO_ROUND48(5*4, 1*32+4, d, a, b, c, h, e, f, g)
DO_ROUND48(6*4, 1*32+8, c, d, a, b, g, h, e, f)
DO_ROUND48(7*4, 1*32+12, b, c, d, a, f, g, h, e)
VMOVDQU XDWORD2, (_XFER + 2*32)(SP)(SRND*2)
VPXOR XDWORD2, XDWORD3, XFER
VMOVDQU XFER, (_XFER + 2*32+68*4*2)(SP)(SRND*2)
DO_ROUND48(8*4, 2*32+0, a, b, c, d, e, f, g, h)
DO_ROUND48(9*4, 2*32+4, d, a, b, c, h, e, f, g)
DO_ROUND48(10*4,2*32+8, c, d, a, b, g, h, e, f)
DO_ROUND48(11*4,2*32+12, b, c, d, a, f, g, h, e)
VMOVDQU XDWORD3, (_XFER + 3*32)(SP)(SRND*2)
VPXOR XDWORD3, XDWORD0, XFER
VMOVDQU XFER, (_XFER + 3*32+68*4*2)(SP)(SRND*2)
DO_ROUND48(12*4, 3*32+0, a, b, c, d, e, f, g, h)
DO_ROUND48(13*4, 3*32+4, d, a, b, c, h, e, f, g)
DO_ROUND48(14*4, 3*32+8, c, d, a, b, g, h, e, f)
DO_ROUND48(15*4, 3*32+12, b, c, d, a, f, g, h, e)
MOVQ dig+0(FP), CTX // d.h[8]
MOVQ _INP(SP), INP
xorm( 0(CTX), a)
xorm( 4(CTX), b)
xorm( 8(CTX), c)
xorm( 12(CTX), d)
xorm( 16(CTX), e)
xorm( 20(CTX), f)
xorm( 24(CTX), g)
xorm( 28(CTX), h)
CMPQ _INP_END(SP), INP
JB done_hash
XORQ SRND, SRND
avx2_loop3: // Do second block using previously scheduled results
DO_ROUND16(0, 16+0, a, b, c, d, e, f, g, h)
DO_ROUND16(4, 16+4, d, a, b, c, h, e, f, g)
DO_ROUND16(8, 16+8, c, d, a, b, g, h, e, f)
DO_ROUND16(12, 16+12, b, c, d, a, f, g, h, e)
ADDQ $16, SRND
CMPQ SRND, $4*16
JB avx2_loop3
avx2_loop4:
DO_ROUND48(0, 16+0,a, b, c, d, e, f, g, h)
DO_ROUND48(4, 16+4,d, a, b, c, h, e, f, g)
DO_ROUND48(8, 16+8,c, d, a, b, g, h, e, f)
DO_ROUND48(12, 16+12, b, c, d, a, f, g, h, e)
ADDQ $16, SRND
CMPQ SRND, $16*16
JB avx2_loop4
MOVQ dig+0(FP), CTX // d.h[8]
MOVQ _INP(SP), INP
ADDQ $64, INP
xorm( 0(CTX), a)
xorm( 4(CTX), b)
xorm( 8(CTX), c)
xorm( 12(CTX), d)
xorm( 16(CTX), e)
xorm( 20(CTX), f)
xorm( 24(CTX), g)
xorm( 28(CTX), h)
CMPQ _INP_END(SP), INP
JA avx2_loop0
JB done_hash
avx2_do_last_block:
VMOVDQU 0(INP), XWORD0
VMOVDQU 16(INP), XWORD1
VMOVDQU 32(INP), XWORD2
VMOVDQU 48(INP), XWORD3
VMOVDQU flip_mask<>(SB), BYTE_FLIP_MASK
VPSHUFB X_BYTE_FLIP_MASK, XWORD0, XWORD0
VPSHUFB X_BYTE_FLIP_MASK, XWORD1, XWORD1
VPSHUFB X_BYTE_FLIP_MASK, XWORD2, XWORD2
VPSHUFB X_BYTE_FLIP_MASK, XWORD3, XWORD3
MOVQ $T256<>(SB), TBL
JMP avx2_last_block_enter
avx2_only_one_block:
// Load initial digest
MOVL 0(CTX), a // a = H0
MOVL 4(CTX), b // b = H1
MOVL 8(CTX), c // c = H2
MOVL 12(CTX), d // d = H3
MOVL 16(CTX), e // e = H4
MOVL 20(CTX), f // f = H5
MOVL 24(CTX), g // g = H6
MOVL 28(CTX), h // h = H7
JMP avx2_do_last_block
done_hash:
VZEROUPPER
RET
// shuffle byte order from LE to BE
DATA flip_mask<>+0x00(SB)/8, $0x0405060700010203
DATA flip_mask<>+0x08(SB)/8, $0x0c0d0e0f08090a0b
DATA flip_mask<>+0x10(SB)/8, $0x0405060700010203
DATA flip_mask<>+0x18(SB)/8, $0x0c0d0e0f08090a0b
GLOBL flip_mask<>(SB), 8, $32
// shuffle xBxA -> 00BA
DATA shuff_00BA<>+0x00(SB)/8, $0x0b0a090803020100
DATA shuff_00BA<>+0x08(SB)/8, $0xFFFFFFFFFFFFFFFF
DATA shuff_00BA<>+0x10(SB)/8, $0x0b0a090803020100
DATA shuff_00BA<>+0x18(SB)/8, $0xFFFFFFFFFFFFFFFF
GLOBL shuff_00BA<>(SB), 8, $32
// shuffle xDxC -> DC00
DATA shuff_DC00<>+0x00(SB)/8, $0xFFFFFFFFFFFFFFFF
DATA shuff_DC00<>+0x08(SB)/8, $0x0b0a090803020100
DATA shuff_DC00<>+0x10(SB)/8, $0xFFFFFFFFFFFFFFFF
DATA shuff_DC00<>+0x18(SB)/8, $0x0b0a090803020100
GLOBL shuff_DC00<>(SB), 8, $32
// rotate of Tj: rotT[i] = Tj << (j mod 32)
DATA T256<>+0x0(SB)/4, $0x79cc4519
DATA T256<>+0x4(SB)/4, $0xf3988a32
DATA T256<>+0x8(SB)/4, $0xe7311465
DATA T256<>+0xc(SB)/4, $0xce6228cb
DATA T256<>+0x10(SB)/4, $0x9cc45197
DATA T256<>+0x14(SB)/4, $0x3988a32f
DATA T256<>+0x18(SB)/4, $0x7311465e
DATA T256<>+0x1c(SB)/4, $0xe6228cbc
DATA T256<>+0x20(SB)/4, $0xcc451979
DATA T256<>+0x24(SB)/4, $0x988a32f3
DATA T256<>+0x28(SB)/4, $0x311465e7
DATA T256<>+0x2c(SB)/4, $0x6228cbce
DATA T256<>+0x30(SB)/4, $0xc451979c
DATA T256<>+0x34(SB)/4, $0x88a32f39
DATA T256<>+0x38(SB)/4, $0x11465e73
DATA T256<>+0x3c(SB)/4, $0x228cbce6
DATA T256<>+0x40(SB)/4, $0x9d8a7a87
DATA T256<>+0x44(SB)/4, $0x3b14f50f
DATA T256<>+0x48(SB)/4, $0x7629ea1e
DATA T256<>+0x4c(SB)/4, $0xec53d43c
DATA T256<>+0x50(SB)/4, $0xd8a7a879
DATA T256<>+0x54(SB)/4, $0xb14f50f3
DATA T256<>+0x58(SB)/4, $0x629ea1e7
DATA T256<>+0x5c(SB)/4, $0xc53d43ce
DATA T256<>+0x60(SB)/4, $0x8a7a879d
DATA T256<>+0x64(SB)/4, $0x14f50f3b
DATA T256<>+0x68(SB)/4, $0x29ea1e76
DATA T256<>+0x6c(SB)/4, $0x53d43cec
DATA T256<>+0x70(SB)/4, $0xa7a879d8
DATA T256<>+0x74(SB)/4, $0x4f50f3b1
DATA T256<>+0x78(SB)/4, $0x9ea1e762
DATA T256<>+0x7c(SB)/4, $0x3d43cec5
DATA T256<>+0x80(SB)/4, $0x7a879d8a
DATA T256<>+0x84(SB)/4, $0xf50f3b14
DATA T256<>+0x88(SB)/4, $0xea1e7629
DATA T256<>+0x8c(SB)/4, $0xd43cec53
DATA T256<>+0x90(SB)/4, $0xa879d8a7
DATA T256<>+0x94(SB)/4, $0x50f3b14f
DATA T256<>+0x98(SB)/4, $0xa1e7629e
DATA T256<>+0x9c(SB)/4, $0x43cec53d
DATA T256<>+0xa0(SB)/4, $0x879d8a7a
DATA T256<>+0xa4(SB)/4, $0x0f3b14f5
DATA T256<>+0xa8(SB)/4, $0x1e7629ea
DATA T256<>+0xac(SB)/4, $0x3cec53d4
DATA T256<>+0xb0(SB)/4, $0x79d8a7a8
DATA T256<>+0xb4(SB)/4, $0xf3b14f50
DATA T256<>+0xb8(SB)/4, $0xe7629ea1
DATA T256<>+0xbc(SB)/4, $0xcec53d43
DATA T256<>+0xc0(SB)/4, $0x9d8a7a87
DATA T256<>+0xc4(SB)/4, $0x3b14f50f
DATA T256<>+0xc8(SB)/4, $0x7629ea1e
DATA T256<>+0xcc(SB)/4, $0xec53d43c
DATA T256<>+0xd0(SB)/4, $0xd8a7a879
DATA T256<>+0xd4(SB)/4, $0xb14f50f3
DATA T256<>+0xd8(SB)/4, $0x629ea1e7
DATA T256<>+0xdc(SB)/4, $0xc53d43ce
DATA T256<>+0xe0(SB)/4, $0x8a7a879d
DATA T256<>+0xe4(SB)/4, $0x14f50f3b
DATA T256<>+0xe8(SB)/4, $0x29ea1e76
DATA T256<>+0xec(SB)/4, $0x53d43cec
DATA T256<>+0xf0(SB)/4, $0xa7a879d8
DATA T256<>+0xf4(SB)/4, $0x4f50f3b1
DATA T256<>+0xf8(SB)/4, $0x9ea1e762
DATA T256<>+0xfc(SB)/4, $0x3d43cec5
GLOBL T256<>(SB), (NOPTR + RODATA), $256
+6
View File
@@ -0,0 +1,6 @@
//go:build !amd64
// +build !amd64
package sm3
var block = blockGeneric
+88
View File
@@ -0,0 +1,88 @@
//go:build ignore
// +build ignore
package sm3
// block 未优化的参考实现
// t[i] = Tj << (j mod 32)
var t = [64]uint32{
0x79cc4519, 0xf3988a32, 0xe7311465, 0xce6228cb, 0x9cc45197, 0x3988a32f, 0x7311465e, 0xe6228cbc,
0xcc451979, 0x988a32f3, 0x311465e7, 0x6228cbce, 0xc451979c, 0x88a32f39, 0x11465e73, 0x228cbce6,
0x9d8a7a87, 0x3b14f50f, 0x7629ea1e, 0xec53d43c, 0xd8a7a879, 0xb14f50f3, 0x629ea1e7, 0xc53d43ce,
0x8a7a879d, 0x14f50f3b, 0x29ea1e76, 0x53d43cec, 0xa7a879d8, 0x4f50f3b1, 0x9ea1e762, 0x3d43cec5,
0x7a879d8a, 0xf50f3b14, 0xea1e7629, 0xd43cec53, 0xa879d8a7, 0x50f3b14f, 0xa1e7629e, 0x43cec53d,
0x879d8a7a, 0x0f3b14f5, 0x1e7629ea, 0x3cec53d4, 0x79d8a7a8, 0xf3b14f50, 0xe7629ea1, 0xcec53d43,
0x9d8a7a87, 0x3b14f50f, 0x7629ea1e, 0xec53d43c, 0xd8a7a879, 0xb14f50f3, 0x629ea1e7, 0xc53d43ce,
0x8a7a879d, 0x14f50f3b, 0x29ea1e76, 0x53d43cec, 0xa7a879d8, 0x4f50f3b1, 0x9ea1e762, 0x3d43cec5,
}
// Block functions the standerd algo, for compare test
func blockRef(dig *digest, p []byte) {
var a, b, c, d, e, f, g, h uint32
var w [16]uint32
for len(p) >= chunk {
a = dig.h[0]
b = dig.h[1]
c = dig.h[2]
d = dig.h[3]
e = dig.h[4]
f = dig.h[5]
g = dig.h[6]
h = dig.h[7]
for i := 0; i < 16; i++ {
j := i * 4
w[i] = uint32(p[j+3]) | uint32(p[j+2])<<8 | uint32(p[j+1])<<16 | uint32(p[j])<<24
}
for i := 0; i < 16; i++ {
x := (a<<12 | a>>20)
ss1 := x + e + t[i]
ss1 = ss1<<7 | ss1>>25
ss2 := ss1 ^ x
tt1 := (a ^ b ^ c) + d + ss2 + (w[i] ^ w[(i+4)&15])
tt2 := (e ^ f ^ g) + h + ss1 + w[i]
d = c
c = b<<9 | b>>23
b = a
a = tt1
h = g
g = f<<19 | f>>13
f = e
e = tt2 ^ (tt2<<9 | tt2>>23) ^ (tt2<<17 | tt2>>15)
tw := w[i] ^ w[(i+7)&15] ^ (w[(i+13)&15]<<15 | w[(i+13)&15]>>17)
w[i] = tw ^ (tw<<15 | tw>>17) ^ (tw<<23 | tw>>9) ^ (w[(i+3)&15]<<7 | w[(i+3)&15]>>25) ^ w[(i+10)&15]
}
for i := 16; i < 64; i++ {
x := (a<<12 | a>>20)
ss1 := x + e + t[i]
ss1 = ss1<<7 | ss1>>25
ss2 := ss1 ^ x
tt1 := ((a & b) | (b & c) | (a & c)) + d + ss2 + (w[i&15] ^ w[(i+4)&15])
tt2 := ((e & f) | (^e & g)) + h + ss1 + w[i&15]
d = c
c = b<<9 | b>>23
b = a
a = tt1
h = g
g = f<<19 | f>>13
f = e
e = tt2 ^ (tt2<<9 | tt2>>23) ^ (tt2<<17 | tt2>>15)
tw := w[i&15] ^ w[(i+7)&15] ^ (w[(i+13)&15]<<15 | w[(i+13)&15]>>17)
w[i&15] = tw ^ (tw<<15 | tw>>17) ^ (tw<<23 | tw>>9) ^ (w[(i+3)&15]<<7 | w[(i+3)&15]>>25) ^ w[(i+10)&15]
}
p = p[chunk:]
dig.h[0] ^= a
dig.h[1] ^= b
dig.h[2] ^= c
dig.h[3] ^= d
dig.h[4] ^= e
dig.h[5] ^= f
dig.h[6] ^= g
dig.h[7] ^= h
}
}
+17
View File
@@ -0,0 +1,17 @@
package sm3
import (
"xdx.jelly/xgcl/gerrors"
)
//go:generate stringer -type=ErrorCode -linecomment -output=errors_string.go errors.go
type ErrorCode gerrors.ErrorCode
func (e ErrorCode) Error() string {
return gerrors.Format(uint32(e), e.String())
}
// error codes
const (
ErrInvalidInput ErrorCode = 0x01003000 + iota //输入不合法
)
+24
View File
@@ -0,0 +1,24 @@
// Code generated by "stringer -type=ErrorCode -linecomment -output=errors_string.go errors.go"; DO NOT EDIT.
package sm3
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[ErrInvalidInput-16789504]
}
const _ErrorCode_name = "输入不合法"
var _ErrorCode_index = [...]uint8{0, 15}
func (i ErrorCode) String() string {
i -= 16789504
if i >= ErrorCode(len(_ErrorCode_index)-1) {
return "ErrorCode(" + strconv.FormatInt(int64(i+16789504), 10) + ")"
}
return _ErrorCode_name[_ErrorCode_index[i]:_ErrorCode_index[i+1]]
}
+27
View File
@@ -0,0 +1,27 @@
package sm3
import "hash"
// NewSm2Precomputed return a Hash which is the internal states after
// d.Write(entl[:])
// d.Write(id)
// d.Write(abg)
func NewSm2Precomputed() hash.Hash {
return &digest{
h: [8]uint32{
0xadadedb5, 0x0446043f,
0x08a87ace, 0xe86d2243,
0x8e232383, 0xbfc81fe2,
0xcf9117c8, 0x4707011d,
},
x: [64]byte{
0x21, 0x53, 0xd0, 0xa9,
0x87, 0x7c, 0xc6, 0x2a,
0x47, 0x40, 0x02, 0xdf,
0x32, 0xe5, 0x21, 0x39,
0xf0, 0xa0,
},
nx: 18,
len: 146,
}
}
+165
View File
@@ -0,0 +1,165 @@
/*
Package sm3 implements the SM3 Hash algorithms
*/
package sm3
import (
"hash"
"xdx.jelly/xgcl/sm"
)
func init() {
// 注册sm.SM3、sm.SM3WithID到sm.hashs中去.
sm.RegisterHash(sm.SM3, New)
sm.RegisterHash(sm.SM3WithID, New)
}
type digest struct {
h [8]uint32
x [chunk]byte
nx int
len uint64
}
// NewDigest return a new digest type, void change `digest` to `Digest`.
// 相比标准库,增加此函数。
// 在上下文明确使用sm3的时候,可以显示用这个函数来获取sm3的digest实例,
// 而不是通过New()得到Hash接口。
func NewDigest() *digest {
d := new(digest)
d.Reset()
return d
}
// New returns a new hash.Hash computing the SM3 checksum. The Hash also
// implements encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to
// marshal and unmarshal the internal state of the hash.
func New() hash.Hash {
return NewDigest()
}
// Reset reset the states
func (d *digest) Reset() {
d.h[0] = init0
d.h[1] = init1
d.h[2] = init2
d.h[3] = init3
d.h[4] = init4
d.h[5] = init5
d.h[6] = init6
d.h[7] = init7
d.nx = 0
d.len = 0
}
/*
MarshalBinary和UnmarshalBinary实现了encoding.BinaryMarshaler和
encoding.BinaryMarshaler接口,可以对Sm3的中间状态转化为byte序列存储。
比如kdf函数要计算SM3(z||cnt) cnt = 1,2,3,4...,可以先update(z),保存此时
状态。
用法:
dig := New()
io.WriteString(dig, "a")
// New 返回的是hash接口, 转换为BinaryMarshaler接口
state, _ := dig.(encoding.BinaryMarshaler).MarshalBinary()
// dig do something
dig.(encoding.BinaryUnmarshaler).UnmarshalBinary(state)
补充:我们增加了NewDigest(), 返回*digest,因此可以直接用赋值保存。
d1 := NewDigest()
// ...
*d2 := *d1
*/
// MarshalBinary implements the encoding.BinaryMarshaler interface
// marshal a digest to []byte to save
// no error return.
func (d *digest) MarshalBinary() ([]byte, error) {
b := make([]byte, 0, marshaledSize)
b = append(b, magic...)
b = appendUint32(b, d.h[0])
b = appendUint32(b, d.h[1])
b = appendUint32(b, d.h[2])
b = appendUint32(b, d.h[3])
b = appendUint32(b, d.h[4])
b = appendUint32(b, d.h[5])
b = appendUint32(b, d.h[6])
b = appendUint32(b, d.h[7])
b = append(b, d.x[:]...)
b = appendUint64(b, d.len)
return b, nil
}
// UnmarshalBinary implements the encoding.BinaryMarshaler interface
// recover a digest from []byte
func (d *digest) UnmarshalBinary(b []byte) error {
if len(b) < marshaledSize || string(b[:len(magic)]) != magic {
return ErrInvalidInput
}
b = b[len(magic):]
b, d.h[0] = consumeUint32(b)
b, d.h[1] = consumeUint32(b)
b, d.h[2] = consumeUint32(b)
b, d.h[3] = consumeUint32(b)
b, d.h[4] = consumeUint32(b)
b, d.h[5] = consumeUint32(b)
b, d.h[6] = consumeUint32(b)
b, d.h[7] = consumeUint32(b)
b = b[copy(d.x[:], b):]
_, d.len = consumeUint64(b)
d.nx = int(d.len) % chunk
return nil
}
// Size returns the size of hash digest
func (d *digest) Size() int { return Size }
// BlockSize return the bytes of one block
func (d *digest) BlockSize() int { return BlockSize }
func (d *digest) Write(p []byte) (nn int, err error) {
nn = len(p)
d.len += uint64(nn)
// try to clear d.x
if d.nx > 0 {
n := copy(d.x[d.nx:], p)
d.nx += n
if d.nx == chunk {
block(d, d.x[:])
d.nx = 0
}
p = p[n:]
}
if len(p) >= chunk {
// n is multiple of chunk
n := len(p) &^ (chunk - 1)
block(d, p[:n])
p = p[n:]
}
if len(p) > 0 {
d.nx = copy(d.x[:], p)
}
return
}
// Sum returns the digest without change the intenal states
func (d *digest) Sum(in []byte) []byte {
// make a copy
d0 := *d
hash := d0.checkSum()
return append(in, hash[:]...)
}
// Sum returns the SM3 checksum of the data.
func Sum(data ...[]byte) [Size]byte {
var d digest
d.Reset()
for _, x := range data {
d.Write(x)
}
return d.checkSum()
}
+30
View File
@@ -0,0 +1,30 @@
package sm3_test
import (
"testing"
"xdx.jelly/xgcl/sm/sm3"
)
// BenchmarkBlockGeneric 性能测试
func BenchmarkBlockGeneric(b *testing.B) {
d := sm3.NewDigest()
buf := make([]byte, 10*1024*1024)
b.SetBytes(int64(len(buf)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
sm3.BlockGeneric(d, buf)
}
}
// BenchmarkBlockAVX2 性能测试
func BenchmarkBlockAVX2(b *testing.B) {
d := sm3.NewDigest()
buf := make([]byte, 10*1024*1024)
b.SetBytes(int64(len(buf)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
sm3.BlockAsmAVX2(d, buf)
}
}
+281
View File
@@ -0,0 +1,281 @@
package sm3
import (
"crypto/rand"
"fmt"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestBlock(t *testing.T) {
d := new(digest)
d.Reset()
p := make([]byte, 64)
for i := range p {
p[i] = 1
}
block(d, p)
expect := [8]uint32{0xb9122804, 0xc515b3c2, 0xb34a42f1, 0x06edad4e, 0x52ecd5c7, 0x8545dd67, 0xf42b4275, 0x900ed3ad}
assert.Equal(t, d.h, expect)
}
// BenchmarkSM3 SM3性能测试
//
// goos: darwin
// goarch: arm64
// pkg: xdx.jelly/xgcl/sm/sm3
// BenchmarkSM3
// BenchmarkSM3-10 34 31783298 ns/op 329.91 MB/s 272 B/op 3 allocs/op
// PASS
// ok xdx.jelly/xgcl/sm/sm3 1.184s
func BenchmarkSM3(b *testing.B) {
buf := make([]byte, 10*1024*1024)
d := New()
b.SetBytes(int64(len(buf)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
d.Write(buf)
d.Sum(nil)
d.Reset()
}
}
var sm3Tests = []struct {
name string
msg []byte
iterations int
want string
}{
{
name: "empty",
msg: []byte{},
iterations: 1,
want: "1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b",
},
{
name: "short",
msg: []byte("abc"),
iterations: 1,
want: "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0",
},
{
name: "long",
msg: []byte("abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"),
iterations: 1,
want: "debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732",
},
{
name: "longlong",
msg: longMsg,
iterations: 1,
want: "c5c13a8f59a97cdeae64f16a2272a9e7dd228cb67912cce1fbe3616c954bcbf3",
},
}
func TestSm3(t *testing.T) {
for _, test := range sm3Tests {
t.Run(test.name, func(t *testing.T) {
d := New()
for i := 0; i < test.iterations; i++ {
for _, c := range test.msg {
d.Write([]byte{c})
}
}
s := fmt.Sprintf("%x", d.Sum(nil))
assert.Equal(t, s, test.want)
})
}
}
func TestSM3(t *testing.T) {
data := make([]byte, 256)
for i := range data {
data[i] = byte(i)
}
for i := 0; i < len(data); i++ {
digest := Sum(data[:i])
fmt.Printf("%x\n", digest[:])
}
}
func TestSpeedReport(t *testing.T) {
msg := make([]byte, 10*1024*1024)
_, _ = rand.Read(msg)
start := time.Now()
times := 100
for i := 0; i < times; i++ {
Sum(msg)
}
end := time.Now()
elapsed := end.Sub(start)
t.Logf("SM3 digest speed: %.2f MBps\n", float64(times*len(msg))/float64(1024*1024)/elapsed.Seconds())
}
var longMsg = []byte{
0x41, 0x6C, 0x69, 0x63, 0x65, 0x42, 0x6F, 0x62,
0x7C, 0xBA, 0x5B, 0x19, 0x06, 0x9E, 0xE6, 0x6A,
0xA7, 0x9D, 0x49, 0x04, 0x13, 0xD1, 0x18, 0x46,
0xB9, 0xBA, 0x76, 0xDD, 0x22, 0x56, 0x7F, 0x80,
0x9C, 0xF2, 0x3B, 0x6D, 0x96, 0x4B, 0xB2, 0x65,
0xA9, 0x76, 0x0C, 0x99, 0xCB, 0x6F, 0x70, 0x63,
0x43, 0xFE, 0xD0, 0x56, 0x37, 0x08, 0x58, 0x64,
0x95, 0x8D, 0x6C, 0x90, 0x90, 0x2A, 0xBA, 0x7D,
0x40, 0x5F, 0xBE, 0xDF, 0x7B, 0x78, 0x15, 0x99,
0x86, 0x1E, 0x91, 0x48, 0x5F, 0xB7, 0x62, 0x3D,
0x27, 0x94, 0xF4, 0x95, 0x03, 0x1A, 0x35, 0x59,
0x8B, 0x49, 0x3B, 0xD4, 0x5B, 0xE3, 0x78, 0x13,
0xAB, 0xC7, 0x10, 0xFC, 0xC1, 0xF3, 0x44, 0x82,
0x32, 0xD9, 0x06, 0xA4, 0x69, 0xEB, 0xC1, 0x21,
0x6A, 0x80, 0x2A, 0x70, 0x52, 0xD5, 0x61, 0x7C,
0xD4, 0x30, 0xFB, 0x56, 0xFB, 0xA7, 0x29, 0xD4,
0x1D, 0x9B, 0xD6, 0x68, 0xE9, 0xEB, 0x96, 0x00,
0x28, 0x54, 0x2F, 0xB6, 0x95, 0x4C, 0x84, 0xBE,
0x6A, 0x5F, 0x29, 0x88, 0xA3, 0x1C, 0xB6, 0x81,
0x7B, 0xA0, 0x78, 0x19, 0x66, 0xFA, 0x83, 0xD9,
0x67, 0x3A, 0x95, 0x77, 0xD3, 0xC0, 0xC1, 0x34,
0x5E, 0x27, 0xC1, 0x9F, 0xC0, 0x2E, 0xD9, 0xAE,
0x37, 0xF5, 0xBB, 0x7B, 0xE9, 0xC0, 0x3C, 0x2B,
0x87, 0xDE, 0x02, 0x75, 0x39, 0xCC, 0xF0, 0x3E,
0x6B, 0x7D, 0x36, 0xDE, 0x4A, 0xB4, 0x5C, 0xD1,
0xA1, 0xAB, 0xFC, 0xD3, 0x0C, 0x57, 0xDB, 0x0F,
0x1A, 0x83, 0x8E, 0x3A, 0x8F, 0x2B, 0xF8, 0x23,
0x47, 0x9C, 0x97, 0x8B, 0xD1, 0x37, 0x23, 0x05,
0x06, 0xEA, 0x62, 0x49, 0xC8, 0x91, 0x04, 0x9E,
0x34, 0x97, 0x47, 0x79, 0x13, 0xAB, 0x89, 0xF5,
0xE2, 0x96, 0x0F, 0x38, 0x2B, 0x1B, 0x5C, 0x8E,
0xE0, 0x9D, 0xE0, 0xFA, 0x49, 0x8B, 0xA9, 0x5C,
0x44, 0x09, 0xD6, 0x30, 0xD3, 0x43, 0xDA, 0x40,
0x4F, 0xEC, 0x93, 0x47, 0x2D, 0xA3, 0x3A, 0x4D,
0xB6, 0x59, 0x90, 0x95, 0xC0, 0xCF, 0x89, 0x5E,
0x3A, 0x7B, 0x99, 0x3E, 0xE5, 0xE4, 0xEB, 0xE3,
0xB9, 0xAB, 0x7D, 0x7D, 0x5F, 0xF2, 0xA3, 0xD1,
0x64, 0x7B, 0xA1, 0x54, 0xC3, 0xE8, 0xE1, 0x85,
0xDF, 0xC3, 0x36, 0x57, 0xC1, 0xF1, 0x28, 0xD4,
0x80, 0xF3, 0xF7, 0xE3, 0xF1, 0x68, 0x01, 0x20,
0x80, 0x29, 0xE1, 0x94, 0x34, 0xC7, 0x33, 0xBB,
0x73, 0xF2, 0x16, 0x93, 0xC6, 0x6F, 0xC2, 0x37,
0x24, 0xDB, 0x26, 0x38, 0x0C, 0x52, 0x62, 0x23,
0xC7, 0x05, 0xDA, 0xF6, 0xBA, 0x18, 0xB7, 0x63,
0xA6, 0x86, 0x23, 0xC8, 0x6A, 0x63, 0x2B, 0x05,
0x0F, 0x63, 0xA0, 0x71, 0xA6, 0xD6, 0x2E, 0xA4,
0x5B, 0x59, 0xA1, 0x94, 0x2D, 0xFF, 0x53, 0x35,
0xD1, 0xA2, 0x32, 0xC9, 0xC5, 0x66, 0x4F, 0xAD,
0x5D, 0x6A, 0xF5, 0x4C, 0x11, 0x41, 0x8B, 0x0D,
0x8C, 0x8E, 0x9D, 0x8D, 0x90, 0x57, 0x80, 0xD5,
0x0E, 0x77, 0x90, 0x67, 0xF2, 0xC4, 0xB1, 0xC8,
0xF8, 0x3A, 0x8B, 0x59, 0xD7, 0x35, 0xBB, 0x52,
0xAF, 0x35, 0xF5, 0x67, 0x30, 0xBD, 0xE5, 0xAC,
0x86, 0x1C, 0xCD, 0x99, 0x78, 0x61, 0x72, 0x67,
0xCE, 0x4A, 0xD9, 0x78, 0x9F, 0x77, 0x73, 0x9E,
0x62, 0xF2, 0xE5, 0x7B, 0x48, 0xC2, 0xFF, 0x26,
0xD2, 0xE9, 0x0A, 0x79, 0xA1, 0xD8, 0x6B, 0x93,
0x9B, 0x1C, 0xA0, 0x8F, 0x64, 0x71, 0x2E, 0x33,
0xAE, 0xDA, 0x3F, 0x44, 0xBD, 0x6C, 0xB6, 0x33,
0xE0, 0xF7, 0x22, 0x21, 0x1E, 0x34, 0x4D, 0x73,
0xEC, 0x9B, 0xBE, 0xBC, 0x92, 0x14, 0x27, 0x65,
0x6B, 0xA5, 0x84, 0xCE, 0x74, 0x2A, 0x2A, 0x3A,
0xB4, 0x1C, 0x15, 0xD3, 0xEF, 0x94, 0xED, 0xEB,
0x8E, 0xF7, 0x4A, 0x2B, 0xDC, 0xDA, 0xAE, 0xCC,
0x09, 0xAB, 0xA5, 0x67, 0x98, 0x1F, 0x64, 0x37,
0x10, 0x52, 0xD6, 0xE9, 0xD1, 0x3E, 0x38, 0x19,
0x09, 0xDF, 0xF7, 0xB2, 0xB4, 0x1E, 0x13, 0xC9,
0x87, 0xD0, 0xA9, 0x06, 0x84, 0x23, 0xB7, 0x69,
0x48, 0x0D, 0xAC, 0xCE, 0x6A, 0x06, 0xF4, 0x92,
0x5F, 0xFE, 0xB9, 0x2A, 0xD8, 0x70, 0xF9, 0x7D,
0xC0, 0x89, 0x31, 0x14, 0xDA, 0x22, 0xA4, 0x4D,
0xBC, 0x9E, 0x7A, 0x8B, 0x6C, 0xA3, 0x1A, 0x0C,
0xF0, 0x46, 0x72, 0x65, 0xA1, 0xFB, 0x48, 0xC7,
0x2C, 0x5C, 0x3B, 0x37, 0xE4, 0xF2, 0xFF, 0x83,
0xDB, 0x33, 0xD9, 0x8C, 0x03, 0x17, 0xBC, 0xBB,
0xBB, 0xF4, 0xAC, 0x6D, 0xF6, 0xB8, 0x9E, 0xCA,
0x58, 0x26, 0x8B, 0x28, 0x00, 0x45, 0xE6, 0x12,
0x6C, 0xED, 0x9E, 0x2D, 0x7C, 0x9C, 0xD3, 0xD5,
0xAD, 0x63, 0x0D, 0xEF, 0xAB, 0x0B, 0x83, 0x15,
0x06, 0x21, 0x80, 0x37, 0xEE, 0x0F, 0x86, 0x1C,
0xF9, 0xB4, 0x3C, 0x78, 0x43, 0x4A, 0xEC, 0x38,
0x0A, 0xE7, 0xBF, 0x3E, 0x1A, 0xEC, 0x0C, 0xB6,
0x7A, 0x03, 0x44, 0x09, 0x06, 0xC7, 0xDF, 0xB3,
0xBC, 0xD4, 0xB6, 0xEE, 0xEB, 0xB7, 0xE3, 0x71,
0xF0, 0x09, 0x4A, 0xD4, 0xA8, 0x16, 0x08, 0x8D,
0x98, 0xDB, 0xC7, 0x91, 0xD0, 0x67, 0x1C, 0xAC,
0xA1, 0x22, 0x36, 0xCD, 0xF8, 0xF3, 0x9E, 0x15,
0xAE, 0xB9, 0x6F, 0xAE, 0xB3, 0x96, 0x06, 0xD5,
0xB0, 0x4A, 0xC5, 0x81, 0x74, 0x6A, 0x66, 0x3D,
0x00, 0xDD, 0x2B, 0x74, 0x16, 0xBA, 0xA9, 0x11,
0x72, 0xE8, 0x9D, 0x53, 0x09, 0xD8, 0x34, 0xF7,
0x8C, 0x1E, 0x31, 0xB4, 0x48, 0x3B, 0xB9, 0x71,
0x85, 0x93, 0x1B, 0xAD, 0x7B, 0xE1, 0xB9, 0xB5,
0x7E, 0xBA, 0xC0, 0x34, 0x9F, 0x85, 0x44, 0x46,
0x9E, 0x60, 0xC3, 0x2F, 0x60, 0x75, 0xFB, 0x04,
0x68, 0xA6, 0x81, 0x47, 0xFF, 0x01, 0x35, 0x37,
0xDF, 0x79, 0x2F, 0xFC, 0xE0, 0x24, 0xF8, 0x57,
0x10, 0xCC, 0x2B, 0x56, 0x1A, 0x62, 0xB6, 0x2D,
0xA3, 0x6A, 0xEF, 0xD6, 0x08, 0x50, 0x71, 0x4F,
0x49, 0x17, 0x0F, 0xD9, 0x4A, 0x00, 0x10, 0xC6,
0xD4, 0xB6, 0x51, 0xB6, 0x4F, 0x3A, 0x3A, 0x5E,
0x58, 0xC9, 0x68, 0x7B, 0xED, 0xDC, 0xD9, 0xE4,
0xFE, 0xDA, 0xB1, 0x6B, 0x88, 0x4D, 0x1F, 0xE6,
0xDF, 0xA1, 0x17, 0xB2, 0xAB, 0x82, 0x1F, 0x74,
0xE0, 0xBF, 0x7A, 0xCD, 0xA2, 0x26, 0x98, 0x59,
0x2A, 0x43, 0x09, 0x68, 0xF1, 0x60, 0x86, 0x06,
0x19, 0x04, 0xCE, 0x20, 0x18, 0x47, 0x93, 0x4B,
0x11, 0xCA, 0x0F, 0x9E, 0x95, 0x28, 0xF5, 0xA9,
0xD0, 0xCE, 0x8F, 0x01, 0x5C, 0x9A, 0xEA, 0x79,
0x93, 0x4F, 0xDD, 0xA6, 0xD3, 0xAB, 0x48, 0xC8,
0x57, 0x1C, 0xE2, 0x35, 0x4B, 0x79, 0x74, 0x2A,
0xA4, 0x98, 0xCB, 0x8C, 0xDD, 0xE6, 0xBD, 0x1F,
0xA5, 0x94, 0x63, 0x45, 0xA1, 0xA6, 0x52, 0xF6,
0xA7, 0x6B, 0x67, 0x77, 0xAD, 0x87, 0xC9, 0x12,
0x4C, 0x7D, 0x70, 0x65, 0xF7, 0x48, 0x08, 0xDB,
0x2E, 0x80, 0x37, 0x1C, 0x70, 0x47, 0x15, 0x80,
0xB0, 0xC7, 0xC4, 0x57, 0xA7, 0x9E, 0xA5, 0xE7,
0x24, 0x2F, 0xA3, 0x1F, 0xF8, 0xE1, 0x39, 0xFA,
0xE1, 0x69, 0xA1, 0x69, 0x92, 0xF5, 0xF0, 0x29,
0x16, 0x26, 0x64, 0xCE, 0x78, 0xB3, 0x33, 0x32,
0x4B, 0x3B, 0xDB, 0x4C, 0x68, 0x2B, 0xF9, 0xB2,
0x06, 0x26, 0xD6, 0x4D, 0xCE, 0x60, 0x3F, 0x33,
0x2E, 0x95, 0x93, 0xF6, 0x2B, 0x67, 0xA6, 0xB0,
0x02, 0xDE, 0xB6, 0xDD, 0x2E, 0x7D, 0x4F, 0xAD,
0x3F, 0x33, 0xC3, 0x8F, 0x20, 0x2D, 0xE2, 0x04,
0x53, 0x27, 0x49, 0x06, 0x11, 0xB2, 0xAE, 0x6F,
0x84, 0x9C, 0xF7, 0x79, 0xB9, 0xB7, 0x4A, 0xD9,
0xBA, 0x6C, 0xF3, 0x97, 0xF6, 0x13, 0x26, 0x12,
0x07, 0x77, 0xCE, 0x46, 0x92, 0xF8, 0x5D, 0xC2,
0xAD, 0xC2, 0x69, 0xD1, 0xB6, 0x23, 0x32, 0x58,
0x2D, 0x82, 0x31, 0x32, 0xA9, 0x71, 0x27, 0x54,
0x77, 0xA0, 0xCF, 0x1D, 0xCC, 0xF4, 0xB2, 0xBF,
0x09, 0x6D, 0x91, 0x10, 0xF7, 0x4E, 0x2A, 0x01,
0xB1, 0xED, 0x06, 0x50, 0x23, 0x33, 0xB2, 0xAB,
0x1A, 0xE6, 0x97, 0xEA, 0x34, 0xF2, 0xEF, 0x8C,
0x6E, 0x47, 0xB0, 0x43, 0x18, 0x31, 0x70, 0x6C,
0xB5, 0xAF, 0xCD, 0x75, 0x75, 0x4F, 0xA7, 0x95,
0x28, 0xF6, 0x5B, 0x36, 0x51, 0xE1, 0x84, 0xBC,
0xED, 0x03, 0x06, 0x61, 0xEE, 0x4A, 0x8D, 0x67,
0x0F, 0xBA, 0xE2, 0x67, 0x96, 0xE8, 0xCD, 0xB6,
0x6F, 0x38, 0x8E, 0xD6, 0x64, 0x4A, 0xF8, 0x51,
0x88, 0x5C, 0x7F, 0x92, 0x4C, 0xC7, 0xCB, 0x20,
0x96, 0x8A, 0xA5, 0x0E, 0x82, 0x30, 0xA3, 0xB3,
0x9C, 0x2B, 0xB5, 0xDD, 0x4D, 0x75, 0x3D, 0x94,
0xBE, 0x5D, 0xD9, 0xA4, 0x27, 0x2C, 0xF8, 0x27,
0x0D, 0xA6, 0x49, 0xCB, 0x8A, 0x63, 0x17, 0x2F,
0x8F, 0xB0, 0x28, 0xCD, 0x95, 0x1E, 0x76, 0x21,
0x58, 0x24, 0xA4, 0xEE, 0x28, 0x40, 0x5D, 0x3C,
0x5E, 0x5D, 0xFD, 0xA6, 0xC7, 0xCE, 0x29, 0x3F,
0x4A, 0x40, 0xAC, 0x8F, 0xC5, 0xB7, 0x16, 0x8F,
0xA5, 0x4A, 0xD3, 0xD0, 0xB8, 0x1A, 0x0F, 0x8F,
0x50, 0xC1, 0x64, 0x36, 0x6C, 0xCD, 0xEC, 0x1C,
0x9A, 0x40, 0xDC, 0xE9, 0xF0, 0xA3, 0x11, 0x33,
0x35, 0xD8, 0x9E, 0xAE, 0xB3, 0x6F, 0x4D, 0x31,
0xBB, 0x67, 0x13, 0x06, 0x4C, 0xDA, 0x88, 0x35,
0xE2, 0xAA, 0x45, 0x29, 0xF4, 0x21, 0x29, 0x32,
0x7C, 0x6F, 0x7E, 0x8A, 0xB7, 0x60, 0x65, 0x4D,
0x58, 0xD1, 0x7E, 0x44, 0x8F, 0x6D, 0x5C, 0xBC,
0xA6, 0x6B, 0xD7, 0xE3, 0x38, 0x10, 0xD2, 0x70,
0xDD, 0x3B, 0x94, 0x36, 0xB1, 0xBF, 0x46, 0xB9,
0xA1, 0x7C, 0x9D, 0x11, 0xA5, 0xA6, 0xB1, 0x48,
0, 0, 0, 1,
}