Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
audiowmark
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Stefan Westerfeld
audiowmark
Commits
b95f6f1d
Commit
b95f6f1d
authored
Feb 24, 2019
by
Stefan Westerfeld
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'a-b-error-correction'
parents
1e1a673c
10f02230
Changes
12
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
625 additions
and
209 deletions
+625
-209
README.adoc
README.adoc
+86
-9
audiowmark.cc
src/audiowmark.cc
+260
-147
ber-test.sh
src/ber-test.sh
+40
-6
convcode.cc
src/convcode.cc
+67
-12
convcode.hh
src/convcode.hh
+8
-4
gen-sync-adoc.sh
src/gen-sync-adoc.sh
+4
-6
gen-sync-mk.sh
src/gen-sync-mk.sh
+10
-10
gen-trunc-adoc.sh
src/gen-trunc-adoc.sh
+36
-0
gen-trunc-mk.sh
src/gen-trunc-mk.sh
+41
-0
random.cc
src/random.cc
+29
-0
random.hh
src/random.hh
+2
-1
testconvcode.cc
src/testconvcode.cc
+42
-14
No files found.
README.adoc
View file @
b95f6f1d
...
...
@@ -2,10 +2,9 @@
== Description
`audiowmark` is an Open Source solution for audio watermarking. A sound file
(typically wav) is read by the software, and a 128-bit message is stored in a
watermark in the output sound file. For human listeners, the files typically
sound the same.
`audiowmark` is an Open Source solution for audio watermarking. A sound file is
read by the software, and a 128-bit message is stored in a watermark in the
output sound file. For human listeners, the files typically sound the same.
However, the 128-bit message can be retrieved from the output sound file. Our
tests show, that even if the file is converted to mp3 or ogg (with bitrate 128
...
...
@@ -22,17 +21,94 @@ later. The algorithm used here is inspired by
Martin Steinebach: Digitale Wasserzeichen für Audiodaten.
Darmstadt University of Technology 2004, ISBN 3-8322-2507-2
== Adding
/Retrieving
a Watermark
== Adding a Watermark
To add a watermark to the soundfile in.wav with a 128-bit message (which is
specified as hex-string):
audiowmark add in.wav out.wav 0123456789abcdef0011223344556677
[subs=+quotes]
....
*$ audiowmark add in.wav out.wav 0123456789abcdef0011223344556677*
Input: in.wav
Output: out.wav
Message: 0123456789abcdef0011223344556677
Strength: 10
To get the 128-bit message from the watermarked file, use:
Time: 3:59
Sample Rate: 48000
Channels: 2
Data Blocks: 4
Volume Norm: 0.987 (-0.12 dB)
....
The most important options for adding a watermark are:
--key <filename>::
Use watermarking key from file <filename> (see <<key>>).
audiowmark get out.wav
--strength <s>::
Set the watermarking strength (see <<strength>>).
== Retrieving a Watermark
To get the 128-bit message from the watermarked file, use:
[subs=+quotes]
....
*$ audiowmark get out.wav*
pattern 0:05 0123456789abcdef0011223344556677 1.324 0.059 A
pattern 0:57 0123456789abcdef0011223344556677 1.413 0.112 B
pattern 0:57 0123456789abcdef0011223344556677 1.368 0.086 AB
pattern 1:49 0123456789abcdef0011223344556677 1.302 0.098 A
pattern 2:40 0123456789abcdef0011223344556677 1.361 0.093 B
pattern 2:40 0123456789abcdef0011223344556677 1.331 0.096 AB
pattern all 0123456789abcdef0011223344556677 1.350 0.054
....
The output of `audiowmark get` is designed to be machine readable. Each line
that starts with `pattern` contains one decoded message. The fields are
seperated by one or more space characters. The first field is a *timestamp*
indicating the position of the data block. The second field is the *decoded
message*. For most purposes this is all you need to know.
The software was designed under the assumption that you - the user - will be
able to decide whether a message is correct or not. To do this, on watermarking
song files, you could list each message you embedded in a database. During
retrieval, you should look up each pattern `audiowmark get` outputs in the
database. If the message is not found, then you should assume that a decoding
error occurred. In our example each pattern was decoded correctly, because
the watermark was not damaged at all, but if you for instance use lossy
compression (with a low bitrate), it may happen that only some of the decoded
patterns are correct. Or none, if the watermark was damaged too much.
The third field is the *sync score* (higher is better). The synchronization
algorithm tries to find valid data blocks in the audio file, that become
candidates for decoding.
The fourth field is the *decoding error* (lower is better). During message
decoding, we use convolutional codes for error correction, to make the
watermarking more robust.
The fifth field is the *block type*. There are two types of data blocks,
A blocks and B blocks. A single data block can be decoded alone, as it
contains a complete message. However, if during watermark detection an
A block followed by a B block was found, these two can be decoded
together (then this field will be AB), resulting in even higher error
correction capacity than one block alone would have.
To improve the error correction capacity even further, the `all` pattern
combines all data blocks that are available. The combined decoded
message will often be the most reliable result (meaning that even if all
other patterns were incorrect, this could still be right).
The most important options for getting a watermark are:
--key <filename>::
Use watermarking key from file <filename> (see <<key>>).
--strength <s>::
Set the watermarking strength (see <<strength>>).
[[key]]
== Watermark Key
Since the software is Open Source, a watermarking key should be used to ensure
...
...
@@ -52,6 +128,7 @@ and can be used for the add/get commands as follows:
audiowmark add --key test.key in.wav out.wav 0123456789abcdef0011223344556677
audiowmark get --key test.key out.wav
[[strength]]
== Watermark Strength
The watermark strength parameter affects how much the watermarking algorithm
...
...
@@ -74,7 +151,7 @@ watermark. Fractional strengths (like 7.5) are possible.
== Dependencies
If you compile from source, audiowmark needs the follwing libraries:
If you compile from source, audiowmark needs the foll
o
wing libraries:
* libfftw3
* libsndfile
...
...
src/audiowmark.cc
View file @
b95f6f1d
This diff is collapsed.
Click to expand it.
src/ber-test.sh
View file @
b95f6f1d
#!/bin/bash
TRANSFORM
=
$1
if
[
"x
$AWM_TRUNCATE
"
!=
"x"
]
;
then
AWM_REPORT
=
truncv
fi
if
[
"x
$AWM_SET
"
==
"x"
]
;
then
AWM_SET
=
small
fi
...
...
@@ -29,7 +32,7 @@ fi
do
for
SEED
in
$AWM_SEEDS
do
echo
$i
echo
in_file
$i
if
[
"x
$AWM_RAND_PATTERN
"
!=
"x"
]
;
then
# random pattern, 128 bit
...
...
@@ -43,12 +46,14 @@ do
# pseudo random pattern, 128 bit
PATTERN
=
4e1243bd22c66e76c2ba9eddc1f91394
fi
echo
in_pattern
$PATTERN
echo
in_flags
$AWM_PARAMS
--test-key
$SEED
audiowmark add
"
$i
"
${
AWM_FILE
}
.wav
$PATTERN
$AWM_PARAMS
--test-key
$SEED
>
/dev/null
if
[
"x
$AWM_RAND_CUT
"
!=
x
]
;
then
CUT
=
$RANDOM
audiowmark cut-start
"
${
AWM_FILE
}
.wav"
"
${
AWM_FILE
}
.wav"
$CUT
TEST_CUT_ARGS
=
"--test-cut
$CUT
"
echo
in_cut
$CUT
else
TEST_CUT_ARGS
=
""
fi
...
...
@@ -85,18 +90,47 @@ do
echo
"unknown transform
$TRANSFORM
"
>
&2
exit
1
fi
# blind decoding
audiowmark cmp
$OUT_FILE
$PATTERN
$AWM_PARAMS
--test-key
$SEED
$TEST_CUT_ARGS
# decoding with original
# audiowmark cmp-delta "$i" t.wav $PATTERN $AWM_PARAMS --test-key $SEED
echo
if
[
"x
$AWM_REPORT
"
==
"xtruncv"
]
;
then
for
TRUNC
in
$AWM_TRUNCATE
do
audiowmark cmp
$OUT_FILE
$PATTERN
$AWM_PARAMS
--test-key
$SEED
$TEST_CUT_ARGS
--test-truncate
$TRUNC
|
sed
"s/^/
$TRUNC
/g"
echo
done
else
audiowmark cmp
$OUT_FILE
$PATTERN
$AWM_PARAMS
--test-key
$SEED
$TEST_CUT_ARGS
echo
fi
rm
-f
${
AWM_FILE
}
.wav
$OUT_FILE
# cleanup temp files
done
done
|
{
if
[
"x
$AWM_REPORT
"
==
"xfer"
]
;
then
awk
'BEGIN { bad = n = 0 } $1 == "match_count" { if ($2 == 0) bad++; n++; } END { print bad, n, bad * 100.0 / n; }'
elif
[
"x
$AWM_REPORT
"
==
"xferv"
]
;
then
awk
'BEGIN { bad = n = 0 } { print "###", $0; } $1 == "match_count" { if ($2 == 0) bad++; n++; } END { print bad, n, bad * 100.0 / n; }'
elif
[
"x
$AWM_REPORT
"
==
"xsync"
]
;
then
awk
'BEGIN { bad = n = 0 } $1 == "sync_match" { bad += (3 - $2) / 3.0; n++; } END { print bad, n, bad * 100.0 / n; }'
elif
[
"x
$AWM_REPORT
"
==
"xsyncv"
]
;
then
awk
'{ print "###", $0; } $1 == "sync_match" { correct += $2; missing += 3 - $2; incorrect += $3-$2; print "correct:", correct, "missing:", missing, "incorrect:", incorrect; }'
elif
[
"x
$AWM_REPORT
"
==
"xtruncv"
]
;
then
awk
' {
print "###", $0;
}
$2 == "match_count" {
if (!n[$1])
{
n[$1] = 0;
bad[$1] = 0;
}
if ($3 == 0)
bad[$1]++;
n[$1]++;
}
END {
for (trunc in n) {
print trunc, bad[trunc], n[trunc], bad[trunc] * 100.0 / n[trunc];
}
}'
else
echo
"unknown report
$AWM_REPORT
"
>
&2
exit
1
...
...
src/convcode.cc
View file @
b95f6f1d
...
...
@@ -22,11 +22,14 @@ parity (unsigned int v)
return
p
;
}
// rate 1/6 code generator poynomial from "In search of a 2dB Coding Gain", Yuen and Vo
// minimum free distance 56
constexpr
unsigned
int
rate
=
6
;
constexpr
unsigned
int
order
=
15
;
constexpr
auto
generators
=
std
::
array
<
unsigned
,
6
>
{
046321
,
051271
,
070535
,
063667
,
073277
,
076531
};
constexpr
auto
ab_generators
=
std
::
array
<
unsigned
,
12
>
{
066561
,
075211
,
071545
,
054435
,
063635
,
052475
,
063543
,
075307
,
052547
,
045627
,
067657
,
051757
};
constexpr
unsigned
int
ab_rate
=
ab_generators
.
size
();
constexpr
unsigned
int
order
=
15
;
/*
constexpr unsigned int order = 9;
...
...
@@ -43,14 +46,45 @@ constexpr unsigned int state_count = (1 << order);
constexpr
unsigned
int
state_mask
=
(
1
<<
order
)
-
1
;
size_t
conv_code_size
(
size_t
msg_size
)
conv_code_size
(
ConvBlockType
block_type
,
size_t
msg_size
)
{
switch
(
block_type
)
{
case
ConvBlockType
:
:
a
:
case
ConvBlockType
:
:
b
:
return
(
msg_size
+
order
)
*
ab_rate
/
2
;
case
ConvBlockType
:
:
ab
:
return
(
msg_size
+
order
)
*
ab_rate
;
default:
assert
(
false
);
}
}
vector
<
unsigned
>
get_block_type_generators
(
ConvBlockType
block_type
)
{
return
(
msg_size
+
order
)
*
rate
;
vector
<
unsigned
>
generators
;
if
(
block_type
==
ConvBlockType
::
a
)
{
for
(
unsigned
int
i
=
0
;
i
<
ab_rate
/
2
;
i
++
)
generators
.
push_back
(
ab_generators
[
i
*
2
]);
}
else
if
(
block_type
==
ConvBlockType
::
b
)
{
for
(
unsigned
int
i
=
0
;
i
<
ab_rate
/
2
;
i
++
)
generators
.
push_back
(
ab_generators
[
i
*
2
+
1
]);
}
else
{
assert
(
block_type
==
ConvBlockType
::
ab
);
generators
.
assign
(
ab_generators
.
begin
(),
ab_generators
.
end
());
}
return
generators
;
}
vector
<
int
>
conv_encode
(
const
vector
<
int
>&
in_bits
)
conv_encode
(
ConvBlockType
block_type
,
const
vector
<
int
>&
in_bits
)
{
auto
generators
=
get_block_type_generators
(
block_type
);
vector
<
int
>
out_vec
;
vector
<
int
>
vec
=
in_bits
;
...
...
@@ -75,8 +109,10 @@ conv_encode (const vector<int>& in_bits)
/* decode using viterbi algorithm */
vector
<
int
>
conv_decode_soft
(
const
vector
<
float
>&
coded_bits
,
float
*
error_out
)
conv_decode_soft
(
ConvBlockType
block_type
,
const
vector
<
float
>&
coded_bits
,
float
*
error_out
)
{
auto
generators
=
get_block_type_generators
(
block_type
);
unsigned
int
rate
=
generators
.
size
();
vector
<
int
>
decoded_bits
;
assert
(
coded_bits
.
size
()
%
rate
==
0
);
...
...
@@ -121,7 +157,7 @@ conv_decode_soft (const vector<float>& coded_bits, float *error_out)
float
delta
=
old_table
[
state
].
delta
;
int
sbit_pos
=
new_state
*
rate
;
for
(
size_t
p
=
0
;
p
<
generators
.
size
()
;
p
++
)
for
(
size_t
p
=
0
;
p
<
rate
;
p
++
)
{
const
float
cbit
=
coded_bits
[
i
+
p
];
const
float
sbit
=
state2bits
[
sbit_pos
+
p
];
...
...
@@ -160,7 +196,7 @@ conv_decode_soft (const vector<float>& coded_bits, float *error_out)
}
vector
<
int
>
conv_decode_hard
(
const
vector
<
int
>&
coded_bits
)
conv_decode_hard
(
ConvBlockType
block_type
,
const
vector
<
int
>&
coded_bits
)
{
/* for the final application, we always want soft decoding, so we don't
* special case hard decoding here, so this will be a little slower than
...
...
@@ -170,5 +206,24 @@ conv_decode_hard (const vector<int>& coded_bits)
for
(
auto
b
:
coded_bits
)
soft_bits
.
push_back
(
b
?
1.0
f
:
0.0
f
);
return
conv_decode_soft
(
soft_bits
);
return
conv_decode_soft
(
block_type
,
soft_bits
);
}
void
conv_print_table
(
ConvBlockType
block_type
)
{
vector
<
int
>
bits
(
100
);
bits
[
0
]
=
1
;
vector
<
int
>
out_bits
=
conv_encode
(
block_type
,
bits
);
auto
generators
=
get_block_type_generators
(
block_type
);
unsigned
int
rate
=
generators
.
size
();
for
(
unsigned
int
r
=
0
;
r
<
rate
;
r
++
)
{
for
(
unsigned
int
i
=
0
;
i
<
order
;
i
++
)
printf
(
"%s%d"
,
i
==
0
?
""
:
" "
,
out_bits
[
i
*
rate
+
r
]);
printf
(
"
\n
"
);
}
}
src/convcode.hh
View file @
b95f6f1d
...
...
@@ -4,9 +4,13 @@
#include <vector>
#include <string>
size_t
conv_code_size
(
size_t
msg_size
);
std
::
vector
<
int
>
conv_encode
(
const
std
::
vector
<
int
>&
in_bits
);
std
::
vector
<
int
>
conv_decode_hard
(
const
std
::
vector
<
int
>&
coded_bits
);
std
::
vector
<
int
>
conv_decode_soft
(
const
std
::
vector
<
float
>&
coded_bits
,
float
*
error_out
=
nullptr
);
enum
class
ConvBlockType
{
a
,
b
,
ab
};
size_t
conv_code_size
(
ConvBlockType
block_type
,
size_t
msg_size
);
std
::
vector
<
int
>
conv_encode
(
ConvBlockType
block_type
,
const
std
::
vector
<
int
>&
in_bits
);
std
::
vector
<
int
>
conv_decode_hard
(
ConvBlockType
block_type
,
const
std
::
vector
<
int
>&
coded_bits
);
std
::
vector
<
int
>
conv_decode_soft
(
ConvBlockType
block_type
,
const
std
::
vector
<
float
>&
coded_bits
,
float
*
error_out
=
nullptr
);
void
conv_print_table
(
ConvBlockType
block_type
);
#endif
/* AUDIOWMARK_CONV_CODE_HH */
src/gen-sync-adoc.sh
View file @
b95f6f1d
...
...
@@ -4,10 +4,9 @@ echo ".sync-codec-resistence"
echo
'[frame="topbot",options="header",cols="<2,6*>1"]'
echo
'|=========================='
echo
-n
"| "
for
D
in
$(
seq
10
-1
5
)
for
STRENGTH
in
$(
seq
10
-1
5
)
do
DELTA
=
$(
printf
"0.0%02d
\n
"
$D
)
echo
-n
"|
$DELTA
"
echo
-n
"|
$STRENGTH
"
done
echo
for
TEST
in
mp3 double-mp3 ogg
...
...
@@ -22,10 +21,9 @@ do
echo
"error: bad TEST
$TEST
???"
exit
1
fi
for
D
in
$(
seq
10
-1
5
)
for
STRENGTH
in
$(
seq
10
-1
5
)
do
DELTA
=
$(
printf
"0.0%02d
\n
"
$D
)
cat
$DELTA
-
$TEST
-
*
|
awk
'{bad += $1; n += $2} END {if (n==0) n=1;fer=100.0*bad/n; bold=fer>0?"*":" ";printf ("| %s%.2f%s", bold, fer, bold)}'
cat
$STRENGTH
-
$TEST
-
*
|
grep
-v
'^#'
|
awk
'{bad += $1; n += $2} END {if (n==0) n=1;fer=100.0*bad/n; bold=fer>0?"*":" ";printf ("| %s%.2f%s", bold, fer, bold)}'
done
echo
done
...
...
src/gen-sync-mk.sh
View file @
b95f6f1d
#!/bin/bash
DELTA_RANGE
=
"0.005 0.006 0.007 0.008 0.009 0.010"
STRENGTH_RANGE
=
$(
seq
5 10
)
SEEDS
=
"
$(
seq
0 19
)
"
echo
-n
"all: "
for
SEED
in
$SEEDS
do
for
DELTA
in
$DELTA
_RANGE
for
STRENGTH
in
$STRENGTH
_RANGE
do
echo
-n
"
$
DELTA
-ogg-
$SEED
$DELTA
-mp3-
$SEED
$DELTA
-double-mp3-
$SEED
"
echo
-n
"
$
STRENGTH
-ogg-
$SEED
$STRENGTH
-mp3-
$SEED
$STRENGTH
-double-mp3-
$SEED
"
done
done
...
...
@@ -17,23 +17,23 @@ echo
for
SEED
in
$SEEDS
do
for
DELTA
in
$DELTA
_RANGE
for
STRENGTH
in
$STRENGTH
_RANGE
do
FILE
=
"
$
DELTA
-ogg-
$SEED
"
FILE
=
"
$
STRENGTH
-ogg-
$SEED
"
echo
"
$FILE
:"
echo
-e
"
\t
( cd ..; AWM_RAND_PATTERN=1 AWM_RAND_CUT=1 AWM_SET=huge2 AWM_PARAMS='--
water-delta
$DELTA
' AWM_REPORT=fer
AWM_SEEDS=
$SEED
AWM_FILE='t-
$FILE
' ber-test.sh ogg 128 ) >x
$FILE
"
echo
-e
"
\t
( cd ..; AWM_RAND_PATTERN=1 AWM_RAND_CUT=1 AWM_SET=huge2 AWM_PARAMS='--
strength
$STRENGTH
' AWM_REPORT=ferv
AWM_SEEDS=
$SEED
AWM_FILE='t-
$FILE
' ber-test.sh ogg 128 ) >x
$FILE
"
echo
-e
"
\t
mv x
$FILE
$FILE
"
echo
FILE
=
"
$
DELTA
-mp3-
$SEED
"
FILE
=
"
$
STRENGTH
-mp3-
$SEED
"
echo
"
$FILE
:"
echo
-e
"
\t
( cd ..; AWM_RAND_PATTERN=1 AWM_RAND_CUT=1 AWM_SET=huge2 AWM_PARAMS='--
water-delta
$DELTA
' AWM_REPORT=fer
AWM_SEEDS=
$SEED
AWM_FILE='t-
$FILE
' ber-test.sh mp3 128 ) >x
$FILE
"
echo
-e
"
\t
( cd ..; AWM_RAND_PATTERN=1 AWM_RAND_CUT=1 AWM_SET=huge2 AWM_PARAMS='--
strength
$STRENGTH
' AWM_REPORT=ferv
AWM_SEEDS=
$SEED
AWM_FILE='t-
$FILE
' ber-test.sh mp3 128 ) >x
$FILE
"
echo
-e
"
\t
mv x
$FILE
$FILE
"
echo
FILE
=
"
$
DELTA
-double-mp3-
$SEED
"
FILE
=
"
$
STRENGTH
-double-mp3-
$SEED
"
echo
"
$FILE
:"
echo
-e
"
\t
( cd ..; AWM_RAND_PATTERN=1 AWM_RAND_CUT=1 AWM_SET=huge2 AWM_PARAMS='--
water-delta
$DELTA
' AWM_REPORT=fer
AWM_SEEDS=
$SEED
AWM_FILE='t-
$FILE
' ber-test.sh double-mp3 128 ) >x
$FILE
"
echo
-e
"
\t
( cd ..; AWM_RAND_PATTERN=1 AWM_RAND_CUT=1 AWM_SET=huge2 AWM_PARAMS='--
strength
$STRENGTH
' AWM_REPORT=ferv
AWM_SEEDS=
$SEED
AWM_FILE='t-
$FILE
' ber-test.sh double-mp3 128 ) >x
$FILE
"
echo
-e
"
\t
mv x
$FILE
$FILE
"
echo
done
...
...
src/gen-trunc-adoc.sh
0 → 100755
View file @
b95f6f1d
#!/bin/bash
TRUNCATE
=
"60 110 245"
for
TRUNC
in
60 110 245
do
echo
".sync-codec-resistence
$TRUNC
"
echo
'[frame="topbot",options="header",cols="<2,6*>1"]'
echo
'|=========================='
echo
-n
"| "
for
STRENGTH
in
$(
seq
10
-1
5
)
do
echo
-n
"|
$STRENGTH
"
done
echo
for
TEST
in
mp3 double-mp3 ogg
do
if
[
$TEST
==
mp3
]
;
then
echo
-n
"| mp3 128kbit/s"
elif
[
$TEST
==
double-mp3
]
;
then
echo
-n
"| double mp3 128kbit/s"
elif
[
$TEST
==
ogg
]
;
then
echo
-n
"| ogg 128kbit/s"
else
echo
"error: bad TEST
$TEST
???"
exit
1
fi
for
STRENGTH
in
$(
seq
10
-1
5
)
do
cat
$STRENGTH
-
$TEST
-
*
|
grep
-v
'^#'
|
grep
^
$TRUNC
|
awk
'{bad += $2; n += $3} END {if (n==0) n=1;fer=100.0*bad/n; bold=fer>0?"*":" ";printf ("| %s%.2f%s", bold, fer, bold)}'
done
echo
done
echo
echo
'|=========================='
done
src/gen-trunc-mk.sh
0 → 100755
View file @
b95f6f1d
#!/bin/bash
STRENGTH_RANGE
=
$(
seq
5 10
)
SEEDS
=
"
$(
seq
0 19
)
"
TRUNCATE
=
"60 110 245"
echo
-n
"all: "
for
SEED
in
$SEEDS
do
for
STRENGTH
in
$STRENGTH_RANGE
do
echo
-n
"
$STRENGTH
-ogg-
$SEED
$STRENGTH
-mp3-
$SEED
$STRENGTH
-double-mp3-
$SEED
"
done
done
echo
echo
for
SEED
in
$SEEDS
do
for
STRENGTH
in
$STRENGTH_RANGE
do
FILE
=
"
$STRENGTH
-ogg-
$SEED
"
echo
"
$FILE
:"
echo
-e
"
\t
( cd ..; AWM_RAND_PATTERN=1 AWM_RAND_CUT=1 AWM_SET=huge2 AWM_PARAMS='--strength
$STRENGTH
' AWM_TRUNCATE='
$TRUNCATE
' AWM_SEEDS=
$SEED
AWM_FILE='t-
$FILE
' ber-test.sh ogg 128 ) >x
$FILE
"
echo
-e
"
\t
mv x
$FILE
$FILE
"
echo
FILE
=
"
$STRENGTH
-mp3-
$SEED
"
echo
"
$FILE
:"
echo
-e
"
\t
( cd ..; AWM_RAND_PATTERN=1 AWM_RAND_CUT=1 AWM_SET=huge2 AWM_PARAMS='--strength
$STRENGTH
' AWM_TRUNCATE='
$TRUNCATE
' AWM_SEEDS=
$SEED
AWM_FILE='t-
$FILE
' ber-test.sh mp3 128 ) >x
$FILE
"
echo
-e
"
\t
mv x
$FILE
$FILE
"
echo
FILE
=
"
$STRENGTH
-double-mp3-
$SEED
"
echo
"
$FILE
:"
echo
-e
"
\t
( cd ..; AWM_RAND_PATTERN=1 AWM_RAND_CUT=1 AWM_SET=huge2 AWM_PARAMS='--strength
$STRENGTH
' AWM_TRUNCATE='
$TRUNCATE
' AWM_SEEDS=
$SEED
AWM_FILE='t-
$FILE
' ber-test.sh double-mp3 128 ) >x
$FILE
"
echo
-e
"
\t
mv x
$FILE
$FILE
"
echo
done
done
src/random.cc
View file @
b95f6f1d
...
...
@@ -10,6 +10,31 @@ using std::vector;
using
std
::
regex
;
using
std
::
regex_match
;
static
void
gcrypt_init
()
{
static
bool
init_ok
=
false
;
if
(
!
init_ok
)
{
/* version check: start libgcrypt initialization */
if
(
!
gcry_check_version
(
GCRYPT_VERSION
))
{
fprintf
(
stderr
,
"audiowmark: libgcrypt version mismatch
\n
"
);
exit
(
1
);
}
/* disable secure memory (assume we run in a controlled environment) */
gcry_control
(
GCRYCTL_DISABLE_SECMEM
,
0
);
/* tell libgcrypt that initialization has completed */
gcry_control
(
GCRYCTL_INITIALIZATION_FINISHED
,
0
);
init_ok
=
true
;
}
}
static
vector
<
unsigned
char
>
aes_key
(
16
);
// 128 bits
static
constexpr
auto
GCRY_CIPHER
=
GCRY_CIPHER_AES128
;
...
...
@@ -55,6 +80,8 @@ print (const string& label, const vector<unsigned char>& data)
Random
::
Random
(
uint64_t
seed
,
Stream
stream
)
{
gcrypt_init
();
vector
<
unsigned
char
>
ctr
=
get_start_counter
(
seed
,
stream
);
// print ("CTR", ctr);
...
...
@@ -201,6 +228,8 @@ Random::load_global_key (const string& key_file)
string
Random
::
gen_key
()
{
gcrypt_init
();
vector
<
unsigned
char
>
key
(
16
);
gcry_randomize
(
&
key
[
0
],
16
,
/* long term key material strength */
GCRY_VERY_STRONG_RANDOM
);
return
vec_to_hex_str
(
key
);
...
...
src/random.hh
View file @
b95f6f1d
...
...
@@ -15,7 +15,8 @@ public:
sync_up_down
=
2
,
pad_up_down
=
3
,
mix
=
4
,
bit_order
=
5
bit_order
=
5
,
frame_position
=
6
};
private
:
gcry_cipher_hd_t
aes_ctr_cipher
;
...
...
src/testconvcode.cc
View file @
b95f6f1d
...
...
@@ -34,10 +34,36 @@ generate_error_vector (size_t n, int errors)
}
return
ev
;
}
static
bool
no_case_equal
(
const
string
&
s1
,
const
string
&
s2
)
{
if
(
s1
.
size
()
!=
s2
.
size
())
return
false
;
return
std
::
equal
(
s1
.
begin
(),
s1
.
end
(),
s2
.
begin
(),
[]
(
char
c1
,
char
c2
)
->
bool
{
return
tolower
(
c1
)
==
tolower
(
c2
);});
}
int
main
(
int
argc
,
char
**
argv
)
{
if
(
argc
==
1
)
string
btype
=
(
argc
>
1
)
?
argv
[
1
]
:
""
;
ConvBlockType
block_type
;
if
(
no_case_equal
(
btype
,
"A"
))
block_type
=
ConvBlockType
::
a
;
else
if
(
no_case_equal
(
btype
,
"B"
))
block_type
=
ConvBlockType
::
b
;
else
if
(
no_case_equal
(
btype
,
"AB"
))
block_type
=
ConvBlockType
::
ab
;
else
{
printf
(
"first argument must be A, B, or AB
\n
"
);
return
1
;
}
if
(
argc
==
2
)
{
vector
<
int
>
in_bits
=
bit_str_to_vec
(
"80f12381"
);
...
...
@@ -46,16 +72,16 @@ main (int argc, char **argv)
printf
(
"%d"
,
b
);
printf
(
"
\n
"
);
vector
<
int
>
coded_bits
=
conv_encode
(
in_bits
);
vector
<
int
>
coded_bits
=
conv_encode
(
block_type
,
in_bits
);
printf
(
"coded vector (n=%zd): "
,
coded_bits
.
size
());
for
(
auto
b
:
coded_bits
)
printf
(
"%d"
,
b
);
printf
(
"
\n
"
);
printf
(
"coded hex: %s
\n
"
,
bit_vec_to_str
(
coded_bits
).
c_str
());
assert
(
coded_bits
.
size
()
==
conv_code_size
(
in_bits
.
size
()));
assert
(
coded_bits
.
size
()
==
conv_code_size
(
block_type
,
in_bits
.
size
()));
vector
<
int
>
decoded_bits
=
conv_decode_hard
(
coded_bits
);
vector
<
int
>
decoded_bits
=
conv_decode_hard
(
block_type
,
coded_bits
);
printf
(
"output vector (k=%zd): "
,
decoded_bits
.
size
());
for
(
auto
b
:
decoded_bits
)
printf
(
"%d"
,
b
);
...
...
@@ -68,9 +94,9 @@ main (int argc, char **argv)
errors
++
;
printf
(
"decoding errors: %d
\n
"
,
errors
);
}
if
(
argc
==
2
&&
string
(
argv
[
1
])
==
"error"
)
if
(
argc
==
3
&&
string
(
argv
[
2
])
==
"error"
)
{
size_t
max_bit_errors
=
conv_code_size
(
128
)
*
0.5
;
size_t
max_bit_errors
=
conv_code_size
(
block_type
,
128
)
*
0.5
;
for
(
size_t
bit_errors
=
0
;
bit_errors
<
max_bit_errors
;
bit_errors
++
)
{
...
...
@@ -84,14 +110,14 @@ main (int argc, char **argv)
while
(
in_bits
.
size
()
!=
128
)
in_bits
.
push_back
(
rand
()
&
1
);
vector
<
int
>
coded_bits
=
conv_encode
(
in_bits
);
vector
<
int
>
coded_bits
=
conv_encode
(
block_type
,
in_bits
);
coded_bit_count
=
coded_bits
.
size
();
vector
<
int
>
error_bits
=
generate_error_vector
(
coded_bits
.
size
(),
bit_errors
);
for
(
size_t
pos
=
0
;
pos
<
coded_bits
.
size
();
pos
++
)
coded_bits
[
pos
]
^=
error_bits
[
pos
];
vector
<
int
>
decoded_bits
=
conv_decode_hard
(
coded_bits
);
vector
<
int
>
decoded_bits
=
conv_decode_hard
(
block_type
,
coded_bits
);
assert
(
decoded_bits
.
size
()
==
128
);
...
...
@@ -105,7 +131,7 @@ main (int argc, char **argv)
printf
(
"%f %f
\n
"
,
(
100.0
*
bit_errors
)
/
coded_bit_count
,
(
100.0
*
bad_decode
)
/
test_size
);
}
}
if
(
argc
==
2
&&
string
(
argv
[
1
])
==
"soft-error"
)
if
(
argc
==
3
&&
string
(
argv
[
2
])
==
"soft-error"
)
{
for
(
double
stddev
=
0
;
stddev
<
1.5
;
stddev
+=
0.01
)
{
...
...
@@ -120,7 +146,7 @@ main (int argc, char **argv)
while
(
in_bits
.
size
()
!=
128
)
in_bits
.
push_back
(
rand
()
&
1
);
vector
<
int
>
coded_bits
=
conv_encode
(
in_bits
);
vector
<
int
>
coded_bits
=
conv_encode
(
block_type
,
in_bits
);
coded_bit_count
=
coded_bits
.
size
();
std
::
default_random_engine
generator
;
...
...
@@ -130,7 +156,7 @@ main (int argc, char **argv)
for
(
auto
b
:
coded_bits
)
recv_bits
.
push_back
(
b
+
dist
(
generator
));
vector
<
int
>
decoded_bits1
=
conv_decode_soft
(
recv_bits
);
vector
<
int
>
decoded_bits1
=
conv_decode_soft
(
block_type
,
recv_bits
);
vector
<
int
>
recv_hard_bits
;
for
(
auto
b
:
recv_bits
)
...
...
@@ -139,7 +165,7 @@ main (int argc, char **argv)
for
(
size_t
x
=
0
;
x
<
recv_hard_bits
.
size
();
x
++
)
local_be
+=
coded_bits
[
x
]
^
recv_hard_bits
[
x
];
vector
<
int
>
decoded_bits2
=
conv_decode_hard
(
recv_hard_bits
);
vector
<
int
>
decoded_bits2
=
conv_decode_hard
(
block_type
,
recv_hard_bits
);
assert
(
decoded_bits1
.
size
()
==
128
);
assert
(
decoded_bits2
.
size
()
==
128
);
...
...
@@ -161,7 +187,7 @@ main (int argc, char **argv)
printf
(
"%f %f %f
\n
"
,
double
(
100
*
local_be
)
/
test_size
/
coded_bit_count
,
(
100.0
*
bad_decode1
)
/
test_size
,
(
100.0
*
bad_decode2
)
/
test_size
);
}
}
if
(
argc
==
2
&&
string
(
argv
[
1
])
==
"perf"
)
if
(
argc
==
3
&&
string
(
argv
[
2
])
==
"perf"
)
{
vector
<
int
>
in_bits
;
while
(
in_bits
.
size
()
!=
128
)
...
...
@@ -171,9 +197,11 @@ main (int argc, char **argv)
const
size_t
runs
=
20
;
for
(
size_t
i
=
0
;
i
<
runs
;
i
++
)
{
vector
<
int
>
out_bits
=
conv_decode_hard
(
conv_encode
(
in_bits
));
vector
<
int
>
out_bits
=
conv_decode_hard
(
block_type
,
conv_encode
(
block_type
,
in_bits
));
assert
(
out_bits
==
in_bits
);
}
printf
(
"%.1f ms/block
\n
"
,
(
gettime
()
-
start_t
)
/
runs
*
1000.0
);
}
if
(
argc
==
3
&&
string
(
argv
[
2
])
==
"table"
)
conv_print_table
(
block_type
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment