v / vlib / crypto / ripemd160 / ripemd160.v
152 lines · 133 sloc · 2.96 KB · 07c796b670d9e498ccb25605af189617f61ec295
Raw
1// Based on: https://github.com/golang/crypto/blob/master/ripemd160/ripemd160.go
2
3module ripemd160
4
5// RIPEMD-160 is designed by Hans Dobbertin, Antoon Bosselaers, and Bart
6// Preneel with specifications available at:
7// http://homes.esat.kuleuven.be/~cosicart/pdf/AB-9601/AB-9601.pdf.
8
9// The size of the checksum in bytes.
10const size = 20
11
12// The block size of the hash algorithm in bytes.
13const block_size = 64
14
15const _s0 = u32(0x67452301)
16const _s1 = u32(0xefcdab89)
17const _s2 = u32(0x98badcfe)
18const _s3 = u32(0x10325476)
19const _s4 = u32(0xc3d2e1f0)
20
21// Digest represents the partial evaluation of a checksum.
22struct Digest {
23mut:
24 s []u32
25 x []u8
26 nx int
27 tc u64
28}
29
30// free the resources taken by the Digest `d`
31@[unsafe]
32pub fn (mut d Digest) free() {
33 $if prealloc {
34 return
35 }
36 unsafe {
37 d.s.free()
38 d.x.free()
39 }
40}
41
42fn (mut d Digest) init() {
43 d.s = []u32{len: 5}
44 d.x = []u8{len: block_size}
45 d.reset()
46}
47
48// reset the state of the Digest `d`
49pub fn (mut d Digest) reset() {
50 d.s[0] = u32(_s0)
51 d.s[1] = u32(_s1)
52 d.s[2] = u32(_s2)
53 d.s[3] = u32(_s3)
54 d.s[4] = u32(_s4)
55 d.nx = 0
56 d.tc = 0
57}
58
59fn (d &Digest) clone() &Digest {
60 return &Digest{
61 ...d
62 s: d.s.clone()
63 x: d.x.clone()
64 }
65}
66
67// new returns a new Digest (implementing hash.Hash) computing the RIPEMD-160 checksum.
68pub fn new() &Digest {
69 mut d := &Digest{}
70 d.init()
71 return d
72}
73
74// size returns the size of the checksum in bytes.
75pub fn (d &Digest) size() int {
76 return size
77}
78
79// block_size returns the block size of the checksum in bytes.
80pub fn (d &Digest) block_size() int {
81 return block_size
82}
83
84// hexhash returns a hexadecimal RIPEMD-160 hash sum `string` of `s`.
85pub fn hexhash(s string) string {
86 mut d := new()
87 d.write(s.bytes()) or { panic(err) }
88 return d.sum([]).hex()
89}
90
91// write writes the contents of `p_` to the internal hash representation.
92pub fn (mut d Digest) write(p_ []u8) !int {
93 unsafe {
94 mut p := p_
95 mut nn := p.len
96 d.tc += u64(nn)
97 if d.nx > 0 {
98 mut n := p.len
99 if n > block_size - d.nx {
100 n = block_size - d.nx
101 }
102 for i := 0; i < n; i++ {
103 d.x[d.nx + i] = p[i]
104 }
105 d.nx += n
106 if d.nx == block_size {
107 block(mut d, d.x[0..])
108 d.nx = 0
109 }
110 p = p[n..]
111 }
112 n := block(mut d, p)
113 p = p[n..]
114 if p.len > 0 {
115 d.nx = copy(mut d.x[..], p)
116 }
117 return nn
118 }
119}
120
121// sum returns the RIPEMD-160 sum of the bytes in `inp`.
122pub fn (d0 &Digest) sum(inp []u8) []u8 {
123 mut d := d0.clone()
124 mut tc := d.tc
125 mut tmp := []u8{len: 64}
126 tmp[0] = 0x80
127 if tc % 64 < 56 {
128 d.write(tmp[0..int(56 - tc % 64)]) or { panic(err) }
129 } else {
130 d.write(tmp[0..int(64 + 56 - tc % 64)]) or { panic(err) }
131 }
132
133 // Length in bits.
134 tc <<= 3
135 for i := u16(0); i < 8; i++ {
136 tmp[i] = u8(tc >> (8 * i))
137 }
138 d.write(tmp[0..8]) or { panic(err) }
139
140 if d.nx != 0 {
141 panic('v_crypto/ripemd160: d.nx != 0: ${d.nx}')
142 }
143
144 mut digest := []u8{len: size}
145 for i, s in d.s {
146 digest[i * 4] = u8(s)
147 digest[i * 4 + 1] = u8(s >> 8)
148 digest[i * 4 + 2] = u8(s >> 16)
149 digest[i * 4 + 3] = u8(s >> 24)
150 }
151 return digest
152}
153